mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-17 22:39:25 +00:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
c914f8c44a | |||
abfda3627c | |||
5b5bfa02db | |||
0fdb072385 | |||
7b4c9d59b0 | |||
bd5923716f | |||
64cc42a23b | |||
325f178763 | |||
fc8d0e52ef | |||
e58348907e | |||
eaba9173ae | |||
2f42b30f87 | |||
35913b95be | |||
8023fa1b76 | |||
4cbe2d1d61 | |||
740036e8d9 | |||
273a7aa9a4 | |||
dccb479c3c | |||
6f5c6e5ebe | |||
8495cc6263 | |||
d242d8dcf4 | |||
864d576e70 | |||
f0127b018e | |||
5eb48a58bf | |||
b690f68c7f | |||
7f19b83828 | |||
98a1ec82db | |||
63313ff964 | |||
210e32bed4 |
65
CHANGELOG.md
65
CHANGELOG.md
@@ -1,5 +1,70 @@
|
||||
# Changelog
|
||||
|
||||
## 0.3.0
|
||||
|
||||
All deprecations has been removed
|
||||
|
||||
* `Repos`:
|
||||
* `Common`:
|
||||
* `KeyValue` and `OneToMany` repos lost their deprecated methods
|
||||
* `OneToMany` write repos got additional extensions for mutation of repo
|
||||
* `KeyValue` write repos got additional extensions for mutation of repo
|
||||
* New interface `MapperRepo` and new classes which are using this:
|
||||
* `KeyValue`
|
||||
* `MapperReadStandardKeyValueRepo`
|
||||
* `MapperWriteStandardKeyValueRepo`
|
||||
* `MapperStandardKeyValueRepo`
|
||||
* `OneToMany`
|
||||
* `MapperReadOneToManyKeyValueRepo`
|
||||
* `MapperWriteOneToManyKeyValueRepo`
|
||||
* `MapperOneToManyKeyValueRepo`
|
||||
* `Exposed`:
|
||||
* CRUD realizations replaced their channels to shared flows
|
||||
|
||||
## 0.2.7
|
||||
|
||||
* `Versions`:
|
||||
* `Coroutines`: `1.4.0` -> `1.4.1`
|
||||
* `Repos`:
|
||||
* `WriteStandardKeyValueRepo` got new methods `set` and `unset` with collections
|
||||
* All standard realizations of repos got collections methods realizations
|
||||
* All old usages of `BroadcastFlow` and `BroadcastChannel` has been replaced with `MutableSharedFlow`
|
||||
* `Ktor`:
|
||||
* `Server`:
|
||||
* Fixed incorrect answer for `keyvalue`
|
||||
|
||||
## 0.2.6
|
||||
|
||||
* `Pagination`
|
||||
* Fixes in function `List#paginate`
|
||||
* Extension property `Pagination#lastIndexExclusive`
|
||||
|
||||
## 0.2.5
|
||||
|
||||
* `Coroutines`
|
||||
* Function `safelyWithoutExceptions`
|
||||
* Extension `CoroutineScope#safeActor`
|
||||
|
||||
## 0.2.4
|
||||
|
||||
* `Versions`
|
||||
* `Serialization`: `1.0.0` -> `1.0.1`
|
||||
* `Common`
|
||||
* Full rework of `DiffUtils`
|
||||
* Data class `Diff` has been added
|
||||
* Extension `Iterable#calculateDiff` has been added
|
||||
* Extension `Iterable#calculateStrictDiff` as replacement for `Iterable#calculateDiff` with
|
||||
`strictComparison` mode enabled
|
||||
* Functions `Diff` (as analog of `Iterable#calculateDiff`) and `StrictDiff` (as analog of
|
||||
`Iterable#calculateStrictDiff`)
|
||||
* `Coroutines`
|
||||
* `BroadcastFlow` now is deprecated
|
||||
* `BroadcastStateFlow` now is deprecated
|
||||
* New extensions for `Flow`s:
|
||||
* `Flow#subscribe`
|
||||
* `Flow#subscribeSafely`
|
||||
* `Flow#subscribeSafelyWithoutExceptions`
|
||||
|
||||
## 0.2.3
|
||||
|
||||
* `Versions`
|
||||
|
@@ -1,10 +1,151 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
fun <T> Iterable<T>.syncWith(
|
||||
other: Iterable<T>,
|
||||
removed: (List<T>) -> Unit = {},
|
||||
added: (List<T>) -> Unit = {}
|
||||
) {
|
||||
removed(filter { it !in other })
|
||||
added(other.filter { it !in this })
|
||||
private inline fun <T> getObject(
|
||||
additional: MutableList<T>,
|
||||
iterator: Iterator<T>
|
||||
): T? = when {
|
||||
additional.isNotEmpty() -> additional.removeFirst()
|
||||
iterator.hasNext() -> iterator.next()
|
||||
else -> null
|
||||
}
|
||||
|
||||
/**
|
||||
* Diff object which contains information about differences between two [Iterable]s
|
||||
*
|
||||
* @see calculateDiff
|
||||
*/
|
||||
data class Diff<T> internal constructor(
|
||||
val removed: List<IndexedValue<T>>,
|
||||
/**
|
||||
* Old-New values pairs
|
||||
*/
|
||||
val replaced: List<Pair<IndexedValue<T>, IndexedValue<T>>>,
|
||||
val added: List<IndexedValue<T>>
|
||||
)
|
||||
|
||||
private inline fun <T> performChanges(
|
||||
potentialChanges: MutableList<Pair<IndexedValue<T>?, IndexedValue<T>?>>,
|
||||
additionalsInOld: MutableList<T>,
|
||||
additionalsInNew: MutableList<T>,
|
||||
changedList: MutableList<Pair<IndexedValue<T>, IndexedValue<T>>>,
|
||||
removedList: MutableList<IndexedValue<T>>,
|
||||
addedList: MutableList<IndexedValue<T>>,
|
||||
strictComparison: Boolean
|
||||
) {
|
||||
var i = -1
|
||||
val (oldObject, newObject) = potentialChanges.lastOrNull() ?: return
|
||||
for ((old, new) in potentialChanges.take(potentialChanges.size - 1)) {
|
||||
i++
|
||||
val oldOneEqualToNewObject = old ?.value === newObject ?.value || (old ?.value == newObject ?.value && !strictComparison)
|
||||
val newOneEqualToOldObject = new ?.value === oldObject ?.value || (new ?.value == oldObject ?.value && !strictComparison)
|
||||
if (oldOneEqualToNewObject || newOneEqualToOldObject) {
|
||||
changedList.addAll(
|
||||
potentialChanges.take(i).mapNotNull {
|
||||
if (it.first != null && it.second != null) it as Pair<IndexedValue<T>, IndexedValue<T>> else null
|
||||
}
|
||||
)
|
||||
val newPotentials = potentialChanges.drop(i).take(potentialChanges.size - i)
|
||||
when {
|
||||
oldOneEqualToNewObject -> {
|
||||
newPotentials.first().second ?.let { addedList.add(it) }
|
||||
newPotentials.drop(1).take(newPotentials.size - 2).forEach { (oldOne, newOne) ->
|
||||
addedList.add(newOne!!)
|
||||
oldOne ?.let { additionalsInOld.add(oldOne.value) }
|
||||
}
|
||||
if (newPotentials.size > 1) {
|
||||
newPotentials.last().first ?.value ?.let { additionalsInOld.add(it) }
|
||||
}
|
||||
}
|
||||
newOneEqualToOldObject -> {
|
||||
newPotentials.first().first ?.let { removedList.add(it) }
|
||||
newPotentials.drop(1).take(newPotentials.size - 2).forEach { (oldOne, newOne) ->
|
||||
removedList.add(oldOne!!)
|
||||
newOne ?.let { additionalsInNew.add(newOne.value) }
|
||||
}
|
||||
if (newPotentials.size > 1) {
|
||||
newPotentials.last().second ?.value ?.let { additionalsInNew.add(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
potentialChanges.clear()
|
||||
return
|
||||
}
|
||||
}
|
||||
if (potentialChanges.isNotEmpty() && potentialChanges.last().let { it.first == null && it.second == null }) {
|
||||
potentialChanges.dropLast(1).forEach { (old, new) ->
|
||||
when {
|
||||
old != null && new != null -> changedList.add(old to new)
|
||||
old != null -> removedList.add(old)
|
||||
new != null -> addedList.add(new)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculating [Diff] object
|
||||
*
|
||||
* @param strictComparison If this parameter set to true, objects which are not equal by links will be used as different
|
||||
* objects. For example, in case of two "Example" string they will be equal by value, but CAN be different by links
|
||||
*/
|
||||
fun <T> Iterable<T>.calculateDiff(
|
||||
other: Iterable<T>,
|
||||
strictComparison: Boolean = false
|
||||
): Diff<T> {
|
||||
var i = -1
|
||||
var j = -1
|
||||
|
||||
val additionalInOld = mutableListOf<T>()
|
||||
val additionalInNew = mutableListOf<T>()
|
||||
|
||||
val oldIterator = iterator()
|
||||
val newIterator = other.iterator()
|
||||
|
||||
val potentiallyChangedObjects = mutableListOf<Pair<IndexedValue<T>?, IndexedValue<T>?>>()
|
||||
val changedObjects = mutableListOf<Pair<IndexedValue<T>, IndexedValue<T>>>()
|
||||
val addedObjects = mutableListOf<IndexedValue<T>>()
|
||||
val removedObjects = mutableListOf<IndexedValue<T>>()
|
||||
|
||||
while (true) {
|
||||
i++
|
||||
j++
|
||||
|
||||
val oldObject = getObject(additionalInOld, oldIterator)
|
||||
val newObject = getObject(additionalInNew, newIterator)
|
||||
|
||||
if (oldObject == null && newObject == null) {
|
||||
break
|
||||
}
|
||||
|
||||
when {
|
||||
oldObject === newObject || (oldObject == newObject && !strictComparison) -> {
|
||||
changedObjects.addAll(potentiallyChangedObjects.map { it as Pair<IndexedValue<T>, IndexedValue<T>> })
|
||||
potentiallyChangedObjects.clear()
|
||||
}
|
||||
else -> {
|
||||
potentiallyChangedObjects.add(oldObject ?.let { IndexedValue(i, oldObject) } to newObject ?.let { IndexedValue(j, newObject) })
|
||||
val previousOldsAdditionsSize = additionalInOld.size
|
||||
val previousNewsAdditionsSize = additionalInNew.size
|
||||
performChanges(potentiallyChangedObjects, additionalInOld, additionalInNew, changedObjects, removedObjects, addedObjects, strictComparison)
|
||||
i -= (additionalInOld.size - previousOldsAdditionsSize)
|
||||
j -= (additionalInNew.size - previousNewsAdditionsSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
potentiallyChangedObjects.add(null to null)
|
||||
performChanges(potentiallyChangedObjects, additionalInOld, additionalInNew, changedObjects, removedObjects, addedObjects, strictComparison)
|
||||
|
||||
return Diff(removedObjects.toList(), changedObjects.toList(), addedObjects.toList())
|
||||
}
|
||||
|
||||
inline fun <T> Diff(old: Iterable<T>, new: Iterable<T>) = old.calculateDiff(new)
|
||||
inline fun <T> StrictDiff(old: Iterable<T>, new: Iterable<T>) = old.calculateDiff(new, true)
|
||||
|
||||
/**
|
||||
* This method call [calculateDiff] with strict mode enabled
|
||||
*/
|
||||
inline fun <T> Iterable<T>.calculateStrictDiff(
|
||||
other: Iterable<T>
|
||||
) = calculateDiff(other, strictComparison = true)
|
||||
|
@@ -0,0 +1,76 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import kotlin.math.floor
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class DiffUtilsTests {
|
||||
@Test
|
||||
fun testThatSimpleRemoveWorks() {
|
||||
val oldList = (0 until 10).toList()
|
||||
val withIndex = oldList.withIndex()
|
||||
|
||||
for (count in 1 .. (floor(oldList.size.toFloat() / 2).toInt())) {
|
||||
for ((i, v) in withIndex) {
|
||||
if (i + count > oldList.lastIndex) {
|
||||
continue
|
||||
}
|
||||
val removedSublist = oldList.subList(i, i + count)
|
||||
oldList.calculateDiff(oldList - removedSublist).apply {
|
||||
assertEquals(
|
||||
removedSublist.mapIndexed { j, o -> IndexedValue(i + j, o) },
|
||||
removed
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testThatSimpleAddWorks() {
|
||||
val oldList = (0 until 10).map { it.toString() }
|
||||
val withIndex = oldList.withIndex()
|
||||
|
||||
for (count in 1 .. (floor(oldList.size.toFloat() / 2).toInt())) {
|
||||
for ((i, v) in withIndex) {
|
||||
if (i + count > oldList.lastIndex) {
|
||||
continue
|
||||
}
|
||||
val addedSublist = oldList.subList(i, i + count).map { "added$it" }
|
||||
val mutable = oldList.toMutableList()
|
||||
mutable.addAll(i, addedSublist)
|
||||
oldList.calculateDiff(mutable).apply {
|
||||
assertEquals(
|
||||
addedSublist.mapIndexed { j, o -> IndexedValue(i + j, o) },
|
||||
added
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testThatSimpleChangesWorks() {
|
||||
val oldList = (0 until 10).map { it.toString() }
|
||||
val withIndex = oldList.withIndex()
|
||||
|
||||
for (step in 0 until oldList.size) {
|
||||
for ((i, v) in withIndex) {
|
||||
val mutable = oldList.toMutableList()
|
||||
val changes = (
|
||||
if (step == 0) i until oldList.size else (i until oldList.size step step)
|
||||
).map { index ->
|
||||
IndexedValue(index, mutable[index]) to IndexedValue(index, "changed$index").also {
|
||||
mutable[index] = it.value
|
||||
}
|
||||
}
|
||||
oldList.calculateDiff(mutable).apply {
|
||||
assertEquals(
|
||||
changes,
|
||||
replaced
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -17,3 +17,15 @@ fun <T> CoroutineScope.actor(
|
||||
return channel
|
||||
}
|
||||
|
||||
inline fun <T> CoroutineScope.safeActor(
|
||||
channelCapacity: Int = Channel.UNLIMITED,
|
||||
noinline onException: ExceptionHandler<Unit> = {},
|
||||
crossinline block: suspend (T) -> Unit
|
||||
): Channel<T> = actor(
|
||||
channelCapacity
|
||||
) {
|
||||
safely(onException) {
|
||||
block(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,21 +0,0 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.channels.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
@Suppress("FunctionName")
|
||||
fun <T> BroadcastFlow(
|
||||
internalChannelSize: Int = Channel.BUFFERED
|
||||
): BroadcastFlow<T> {
|
||||
val channel = BroadcastChannel<T>(internalChannelSize)
|
||||
|
||||
return BroadcastFlow(
|
||||
channel,
|
||||
channel.asFlow()
|
||||
)
|
||||
}
|
||||
|
||||
class BroadcastFlow<T> internal constructor(
|
||||
private val channel: BroadcastChannel<T>,
|
||||
private val flow: Flow<T>
|
||||
): Flow<T> by flow, SendChannel<T> by channel
|
@@ -1,63 +0,0 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.BroadcastChannel
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
const val defaultBroadcastStateFlowReplayCacheSize = 1
|
||||
|
||||
class BroadcastStateFlow<T> internal constructor(
|
||||
parentFlow: Flow<T>,
|
||||
initial: T,
|
||||
replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize,
|
||||
replayScope: CoroutineScope
|
||||
) : StateFlow<T>, Flow<T> by parentFlow {
|
||||
private val deque = ArrayDeque<T>(1).also {
|
||||
it.add(initial)
|
||||
}
|
||||
override val replayCache: List<T>
|
||||
get() = deque.toList()
|
||||
override val value: T
|
||||
get() = deque.last()
|
||||
|
||||
init {
|
||||
if (replayCacheSize < 1) {
|
||||
error("Replay cache size can't be less than 1, but was $replayCacheSize")
|
||||
}
|
||||
parentFlow.onEach {
|
||||
deque.addLast(it)
|
||||
if (deque.size > replayCacheSize) {
|
||||
deque.removeFirst()
|
||||
}
|
||||
}.launchIn(replayScope)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> BroadcastChannel<T>.asStateFlow(
|
||||
value: T,
|
||||
scope: CoroutineScope,
|
||||
replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize
|
||||
): StateFlow<T> = BroadcastStateFlow(asFlow(), value, replayCacheSize, scope)
|
||||
|
||||
fun <T> BroadcastChannel<T?>.asStateFlow(
|
||||
scope: CoroutineScope,
|
||||
replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize
|
||||
): StateFlow<T?> = asStateFlow(null, scope, replayCacheSize)
|
||||
|
||||
fun <T> broadcastStateFlow(
|
||||
initial: T, scope: CoroutineScope,
|
||||
channelSize: Int = Channel.BUFFERED,
|
||||
replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize
|
||||
) = BroadcastChannel<T>(
|
||||
channelSize
|
||||
).let {
|
||||
it to it.asStateFlow(initial, scope, replayCacheSize)
|
||||
}
|
||||
|
||||
fun <T> broadcastStateFlow(
|
||||
scope: CoroutineScope,
|
||||
channelSize: Int = Channel.BUFFERED,
|
||||
replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize
|
||||
) = broadcastStateFlow<T?>(null, scope, channelSize, replayCacheSize)
|
||||
|
@@ -0,0 +1,37 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
/**
|
||||
* Shortcut for chain if [Flow.onEach] and [Flow.launchIn]
|
||||
*/
|
||||
inline fun <T> Flow<T>.subscribe(scope: CoroutineScope, noinline block: suspend (T) -> Unit) = onEach(block).launchIn(scope)
|
||||
|
||||
/**
|
||||
* Use [subscribe], but all [block]s will be called inside of [safely] function.
|
||||
* Use [onException] to set up your reaction for [Throwable]s
|
||||
*/
|
||||
inline fun <T> Flow<T>.subscribeSafely(
|
||||
scope: CoroutineScope,
|
||||
noinline onException: ExceptionHandler<Unit> = { throw it },
|
||||
noinline block: suspend (T) -> Unit
|
||||
) = subscribe(scope) {
|
||||
safely(onException) {
|
||||
block(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use [subscribeSafelyWithoutExceptions], but all exceptions inside of [safely] will be skipped
|
||||
*/
|
||||
inline fun <T> Flow<T>.subscribeSafelyWithoutExceptions(
|
||||
scope: CoroutineScope,
|
||||
noinline block: suspend (T) -> Unit
|
||||
) = subscribeSafely(
|
||||
scope,
|
||||
{},
|
||||
block
|
||||
)
|
@@ -21,3 +21,10 @@ suspend inline fun <T> safely(
|
||||
onException(e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for [safely] without exception handler (instead of this you will receive null as a result)
|
||||
*/
|
||||
suspend inline fun <T> safelyWithoutExceptions(
|
||||
noinline block: suspend CoroutineScope.() -> T
|
||||
): T? = safely({ null }, block)
|
||||
|
@@ -5,8 +5,8 @@ kotlin.incremental=true
|
||||
kotlin.incremental.js=true
|
||||
|
||||
kotlin_version=1.4.10
|
||||
kotlin_coroutines_version=1.4.0
|
||||
kotlin_serialisation_core_version=1.0.0
|
||||
kotlin_coroutines_version=1.4.1
|
||||
kotlin_serialisation_core_version=1.0.1
|
||||
kotlin_exposed_version=0.28.1
|
||||
|
||||
ktor_version=1.4.1
|
||||
@@ -19,4 +19,4 @@ github_release_plugin_version=2.2.12
|
||||
uuidVersion=0.2.2
|
||||
|
||||
group=dev.inmo
|
||||
version=0.2.3
|
||||
version=0.3.0
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@@ -4,7 +4,8 @@ import dev.inmo.micro_utils.coroutines.safely
|
||||
import dev.inmo.micro_utils.ktor.common.*
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.features.websocket.ws
|
||||
import io.ktor.http.cio.websocket.*
|
||||
import io.ktor.http.cio.websocket.Frame
|
||||
import io.ktor.http.cio.websocket.readBytes
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
|
@@ -4,7 +4,8 @@ import dev.inmo.micro_utils.ktor.common.*
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.request.post
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
|
||||
typealias BodyPair<T> = Pair<SerializationStrategy<T>, T>
|
||||
|
||||
|
@@ -22,13 +22,11 @@ fun <T> Route.includeWebsocketHandling(
|
||||
converter: (T) -> StandardKtorSerialInputData
|
||||
) {
|
||||
webSocket(suburl) {
|
||||
// println("connected")
|
||||
safely {
|
||||
flow.collect {
|
||||
send(converter(it))
|
||||
}
|
||||
}
|
||||
// println("disconnected")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -7,8 +7,8 @@ import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.request.receive
|
||||
import io.ktor.response.respond
|
||||
import io.ktor.response.respondBytes
|
||||
import io.ktor.util.toByteArray
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
|
||||
suspend fun <T> ApplicationCall.unianswer(
|
||||
answerSerializer: SerializationStrategy<T>,
|
||||
|
@@ -28,6 +28,15 @@ interface Pagination {
|
||||
val Pagination.firstIndex: Int
|
||||
get() = page * size
|
||||
|
||||
/**
|
||||
* Last number in index of objects. In fact, one [Pagination] object represent data in next range:
|
||||
*
|
||||
* [[firstIndex], [lastIndex]]; That means, that for [Pagination] with [Pagination.size] == 10 and [Pagination.page] == 1
|
||||
* you will retrieve [Pagination.firstIndex] == 10 and [Pagination.lastIndex] == 19. Here [Pagination.lastIndexExclusive] == 20
|
||||
*/
|
||||
val Pagination.lastIndexExclusive: Int
|
||||
get() = firstIndex + size
|
||||
|
||||
/**
|
||||
* Last number in index of objects. In fact, one [Pagination] object represent data in next range:
|
||||
*
|
||||
@@ -35,7 +44,7 @@ val Pagination.firstIndex: Int
|
||||
* you will retrieve [Pagination.firstIndex] == 10 and [Pagination.lastIndex] == 19.
|
||||
*/
|
||||
val Pagination.lastIndex: Int
|
||||
get() = firstIndex + size - 1
|
||||
get() = lastIndexExclusive - 1
|
||||
|
||||
/**
|
||||
* Calculates pages count for given [datasetSize]
|
||||
|
@@ -21,7 +21,12 @@ fun <T> Iterable<T>.paginate(with: Pagination): PaginationResult<T> {
|
||||
}
|
||||
|
||||
fun <T> List<T>.paginate(with: Pagination): PaginationResult<T> {
|
||||
return subList(with.firstIndex, with.lastIndex + 1).createPaginationResult(
|
||||
val firstIndex = maxOf(with.firstIndex, 0)
|
||||
val lastIndex = minOf(with.lastIndexExclusive, size)
|
||||
if (firstIndex > lastIndex) {
|
||||
return emptyPaginationResult()
|
||||
}
|
||||
return subList(firstIndex, lastIndex).createPaginationResult(
|
||||
with,
|
||||
size.toLong()
|
||||
)
|
||||
|
@@ -0,0 +1,9 @@
|
||||
package dev.inmo.micro_utils.repos
|
||||
|
||||
interface MapperRepo<FromKey, FromValue, ToKey, ToValue> {
|
||||
suspend fun FromKey.toOutKey() = this as ToKey
|
||||
suspend fun FromValue.toOutValue() = this as ToValue
|
||||
|
||||
suspend fun ToKey.toInnerKey() = this as FromKey
|
||||
suspend fun ToValue.toInnerValue() = this as FromValue
|
||||
}
|
@@ -35,59 +35,51 @@ interface ReadOneToManyKeyValueRepo<Key, Value> : Repo {
|
||||
}
|
||||
}
|
||||
}
|
||||
@Deprecated("Renamed", ReplaceWith("ReadOneToManyKeyValueRepo", "dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo"))
|
||||
typealias OneToManyReadKeyValueRepo<Key, Value> = ReadOneToManyKeyValueRepo<Key, Value>
|
||||
|
||||
interface WriteOneToManyKeyValueRepo<Key, Value> : Repo {
|
||||
val onNewValue: Flow<Pair<Key, Value>>
|
||||
val onValueRemoved: Flow<Pair<Key, Value>>
|
||||
val onDataCleared: Flow<Key>
|
||||
|
||||
suspend fun add(toAdd: Map<Key, List<Value>>) = toAdd.forEach { (k, values) ->
|
||||
values.forEach { v ->
|
||||
add(k, v)
|
||||
}
|
||||
}
|
||||
@Deprecated("Will be extracted as extension for other add method")
|
||||
suspend fun add(k: Key, v: Value)
|
||||
suspend fun add(toAdd: Map<Key, List<Value>>)
|
||||
|
||||
suspend fun remove(toRemove: Map<Key, List<Value>>) = toRemove.forEach { (k, values) ->
|
||||
values.forEach { v ->
|
||||
remove(k, v)
|
||||
}
|
||||
}
|
||||
@Deprecated("Will be extracted as extension for other remove method")
|
||||
suspend fun remove(k: Key, v: Value)
|
||||
suspend fun remove(toRemove: Map<Key, List<Value>>)
|
||||
|
||||
suspend fun clear(k: Key)
|
||||
}
|
||||
@Deprecated("Renamed", ReplaceWith("WriteOneToManyKeyValueRepo", "dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo"))
|
||||
typealias OneToManyWriteKeyValueRepo<Key, Value> = WriteOneToManyKeyValueRepo<Key, Value>
|
||||
|
||||
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.add(
|
||||
keysAndValues: List<Pair<Key, List<Value>>>
|
||||
) = add(keysAndValues.toMap())
|
||||
|
||||
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.add(
|
||||
vararg keysAndValues: Pair<Key, List<Value>>
|
||||
) = add(keysAndValues.toMap())
|
||||
|
||||
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.add(
|
||||
k: Key, v: List<Value>
|
||||
) = add(mapOf(k to v))
|
||||
|
||||
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.add(
|
||||
k: Key, vararg v: Value
|
||||
) = add(k, v.toList())
|
||||
|
||||
interface OneToManyKeyValueRepo<Key, Value> : ReadOneToManyKeyValueRepo<Key, Value>, WriteOneToManyKeyValueRepo<Key, Value>
|
||||
|
||||
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.add(
|
||||
k: Key,
|
||||
vararg v: Value
|
||||
) = add(mapOf(k to v.toList()))
|
||||
|
||||
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.add(
|
||||
keysAndValues: List<Pair<Key, List<Value>>>
|
||||
) = add(keysAndValues.toMap())
|
||||
|
||||
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.add(
|
||||
vararg keysAndValues: Pair<Key, List<Value>>
|
||||
) = add(keysAndValues.toMap())
|
||||
|
||||
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.remove(
|
||||
k: Key,
|
||||
vararg v: Value
|
||||
) = remove(mapOf(k to v.toList()))
|
||||
|
||||
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.remove(
|
||||
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
|
||||
keysAndValues: List<Pair<Key, List<Value>>>
|
||||
) = remove(keysAndValues.toMap())
|
||||
|
||||
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.remove(
|
||||
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
|
||||
vararg keysAndValues: Pair<Key, List<Value>>
|
||||
) = remove(keysAndValues.toMap())
|
||||
|
||||
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
|
||||
k: Key,
|
||||
v: List<Value>
|
||||
) = remove(mapOf(k to v))
|
||||
|
||||
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
|
||||
k: Key,
|
||||
vararg v: Value
|
||||
) = remove(k, v.toList())
|
||||
|
@@ -16,8 +16,20 @@ interface WriteStandardKeyValueRepo<Key, Value> : Repo {
|
||||
val onNewValue: Flow<Pair<Key, Value>>
|
||||
val onValueRemoved: Flow<Key>
|
||||
|
||||
suspend fun set(k: Key, v: Value)
|
||||
suspend fun unset(k: Key)
|
||||
suspend fun set(toSet: Map<Key, Value>)
|
||||
suspend fun unset(toUnset: List<Key>)
|
||||
}
|
||||
|
||||
suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.set(
|
||||
vararg toSet: Pair<Key, Value>
|
||||
) = set(toSet.toMap())
|
||||
|
||||
suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.set(
|
||||
k: Key, v: Value
|
||||
) = set(k to v)
|
||||
|
||||
suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.unset(
|
||||
vararg k: Key
|
||||
) = unset(k.toList())
|
||||
|
||||
interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value>, WriteStandardKeyValueRepo<Key, Value>
|
@@ -0,0 +1,84 @@
|
||||
package dev.inmo.micro_utils.repos.mappers
|
||||
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
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>,
|
||||
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||
) : ReadStandardKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper {
|
||||
override suspend fun get(k: FromKey): FromValue? = to.get(
|
||||
k.toOutKey()
|
||||
) ?.toInnerValue()
|
||||
|
||||
override suspend fun values(
|
||||
pagination: Pagination,
|
||||
reversed: Boolean
|
||||
): PaginationResult<FromValue> = to.values(
|
||||
pagination,
|
||||
reversed
|
||||
).let {
|
||||
PaginationResult(
|
||||
it.page,
|
||||
it.pagesNumber,
|
||||
it.results.map { it.toInnerValue() },
|
||||
it.size
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun keys(
|
||||
pagination: Pagination,
|
||||
reversed: Boolean
|
||||
): PaginationResult<FromKey> = to.keys(
|
||||
pagination,
|
||||
reversed
|
||||
).let {
|
||||
PaginationResult(
|
||||
it.page,
|
||||
it.pagesNumber,
|
||||
it.results.map { it.toInnerKey() },
|
||||
it.size
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun contains(key: FromKey): Boolean = to.contains(
|
||||
key.toOutKey()
|
||||
)
|
||||
|
||||
override suspend fun count(): Long = to.count()
|
||||
}
|
||||
|
||||
open class MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
||||
private val to: WriteStandardKeyValueRepo<ToKey, ToValue>,
|
||||
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||
) : WriteStandardKeyValueRepo<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()
|
||||
}
|
||||
override val onValueRemoved: Flow<FromKey> = to.onValueRemoved.map { k ->
|
||||
k.toInnerKey()
|
||||
}
|
||||
|
||||
override suspend fun set(toSet: Map<FromKey, FromValue>) = to.set(
|
||||
toSet.map { (k, v) ->
|
||||
k.toOutKey() to v.toOutValue()
|
||||
}.toMap()
|
||||
)
|
||||
|
||||
override suspend fun unset(toUnset: List<FromKey>) = to.unset(
|
||||
toUnset.map { k ->
|
||||
k.toOutKey()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
open class MapperStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
||||
private val to: StandardKeyValueRepo<ToKey, ToValue>,
|
||||
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||
) : StandardKeyValueRepo<FromKey, FromValue>,
|
||||
MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper,
|
||||
ReadStandardKeyValueRepo<FromKey, FromValue> by MapperReadStandardKeyValueRepo(to, mapper),
|
||||
WriteStandardKeyValueRepo<FromKey, FromValue> by MapperWriteStandardKeyValueRepo(to, mapper)
|
@@ -0,0 +1,87 @@
|
||||
package dev.inmo.micro_utils.repos.mappers
|
||||
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
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>,
|
||||
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||
) : ReadOneToManyKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper {
|
||||
override suspend fun get(
|
||||
k: FromKey,
|
||||
pagination: Pagination,
|
||||
reversed: Boolean
|
||||
): PaginationResult<FromValue> = to.get(
|
||||
k.toOutKey(),
|
||||
pagination,
|
||||
reversed
|
||||
).let {
|
||||
PaginationResult(
|
||||
it.page,
|
||||
it.pagesNumber,
|
||||
it.results.map { it.toInnerValue() },
|
||||
it.size
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun keys(
|
||||
pagination: Pagination,
|
||||
reversed: Boolean
|
||||
): PaginationResult<FromKey> = to.keys(
|
||||
pagination,
|
||||
reversed
|
||||
).let {
|
||||
PaginationResult(
|
||||
it.page,
|
||||
it.pagesNumber,
|
||||
it.results.map { it.toInnerKey() },
|
||||
it.size
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun contains(k: FromKey): Boolean = to.contains(k.toOutKey())
|
||||
override suspend fun contains(k: FromKey, v: FromValue): Boolean = to.contains(k.toOutKey(), v.toOutValue())
|
||||
|
||||
override suspend fun count(): Long = to.count()
|
||||
override suspend fun count(k: FromKey): Long = to.count(k.toOutKey())
|
||||
}
|
||||
|
||||
open class MapperWriteOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
||||
private val to: WriteOneToManyKeyValueRepo<ToKey, ToValue>,
|
||||
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||
) : WriteOneToManyKeyValueRepo<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()
|
||||
}
|
||||
override val onValueRemoved: Flow<Pair<FromKey, FromValue>> = to.onValueRemoved.map { (k, v) ->
|
||||
k.toInnerKey() to v.toInnerValue()
|
||||
}
|
||||
override val onDataCleared: Flow<FromKey> = to.onDataCleared.map { k ->
|
||||
k.toInnerKey()
|
||||
}
|
||||
|
||||
override suspend fun add(toAdd: Map<FromKey, List<FromValue>>) = to.add(
|
||||
toAdd.map { (k, v) ->
|
||||
k.toOutKey() to v.map { it.toOutValue() }
|
||||
}.toMap()
|
||||
)
|
||||
|
||||
override suspend fun remove(toRemove: Map<FromKey, List<FromValue>>) = to.remove(
|
||||
toRemove.map { (k, v) ->
|
||||
k.toOutKey() to v.map { it.toOutValue() }
|
||||
}.toMap()
|
||||
)
|
||||
|
||||
override suspend fun clear(k: FromKey) = to.clear(k.toOutKey())
|
||||
}
|
||||
|
||||
open class MapperOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
||||
private val to: OneToManyKeyValueRepo<ToKey, ToValue>,
|
||||
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||
) : OneToManyKeyValueRepo<FromKey, FromValue>,
|
||||
MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper,
|
||||
ReadOneToManyKeyValueRepo<FromKey, FromValue> by MapperReadOneToManyKeyValueRepo(to, mapper),
|
||||
WriteOneToManyKeyValueRepo<FromKey, FromValue> by MapperWriteOneToManyKeyValueRepo(to, mapper)
|
@@ -1,9 +1,7 @@
|
||||
package dev.inmo.micro_utils.repos.exposed
|
||||
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
|
||||
abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||
flowsChannelsSize: Int = Channel.BUFFERED,
|
||||
flowsChannelsSize: Int = 0,
|
||||
tableName: String = ""
|
||||
) :
|
||||
AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||
|
@@ -3,28 +3,27 @@ package dev.inmo.micro_utils.repos.exposed
|
||||
import dev.inmo.micro_utils.repos.UpdatedValuePair
|
||||
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
|
||||
import kotlinx.coroutines.channels.BroadcastChannel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.*
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.statements.InsertStatement
|
||||
import org.jetbrains.exposed.sql.statements.UpdateStatement
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||
flowsChannelsSize: Int = 64,
|
||||
flowsChannelsSize: Int = 0,
|
||||
tableName: String = ""
|
||||
) :
|
||||
AbstractExposedReadCRUDRepo<ObjectType, IdType>(tableName),
|
||||
ExposedCRUDRepo<ObjectType, IdType>,
|
||||
WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>
|
||||
{
|
||||
protected val newObjectsChannel = BroadcastChannel<ObjectType>(flowsChannelsSize)
|
||||
protected val updateObjectsChannel = BroadcastChannel<ObjectType>(flowsChannelsSize)
|
||||
protected val deleteObjectsIdsChannel = BroadcastChannel<IdType>(flowsChannelsSize)
|
||||
protected val newObjectsChannel = MutableSharedFlow<ObjectType>(flowsChannelsSize)
|
||||
protected val updateObjectsChannel = MutableSharedFlow<ObjectType>(flowsChannelsSize)
|
||||
protected val deleteObjectsIdsChannel = MutableSharedFlow<IdType>(flowsChannelsSize)
|
||||
|
||||
override val newObjectsFlow: Flow<ObjectType> = newObjectsChannel.asFlow()
|
||||
override val updatedObjectsFlow: Flow<ObjectType> = updateObjectsChannel.asFlow()
|
||||
override val deletedObjectsIdsFlow: Flow<IdType> = deleteObjectsIdsChannel.asFlow()
|
||||
override val newObjectsFlow: Flow<ObjectType> = newObjectsChannel.asSharedFlow()
|
||||
override val updatedObjectsFlow: Flow<ObjectType> = updateObjectsChannel.asSharedFlow()
|
||||
override val deletedObjectsIdsFlow: Flow<IdType> = deleteObjectsIdsChannel.asSharedFlow()
|
||||
|
||||
abstract val InsertStatement<Number>.asObject: ObjectType
|
||||
abstract val selectByIds: SqlExpressionBuilder.(List<out IdType>) -> Op<Boolean>
|
||||
@@ -45,7 +44,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||
values.map { value -> createWithoutNotification(value) }
|
||||
}.also {
|
||||
it.forEach {
|
||||
newObjectsChannel.send(it)
|
||||
newObjectsChannel.emit(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +74,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||
onBeforeUpdate(listOf(id to value))
|
||||
return updateWithoutNotification(id, value).also {
|
||||
if (it != null) {
|
||||
updateObjectsChannel.send(it)
|
||||
updateObjectsChannel.emit(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,7 +88,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||
} as List<ObjectType>
|
||||
).also {
|
||||
it.forEach {
|
||||
updateObjectsChannel.send(it)
|
||||
updateObjectsChannel.emit(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package dev.inmo.micro_utils.repos.exposed
|
||||
|
||||
import dev.inmo.micro_utils.repos.Repo
|
||||
import org.jetbrains.exposed.sql.*
|
||||
|
||||
interface ExposedCRUDRepo<ObjectType, IdType> : ExposedRepo {
|
||||
|
@@ -1,11 +1,9 @@
|
||||
package dev.inmo.micro_utils.repos.exposed.keyvalue
|
||||
|
||||
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.exposed.*
|
||||
import kotlinx.coroutines.channels.BroadcastChannel
|
||||
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.*
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
@@ -20,35 +18,45 @@ open class ExposedKeyValueRepo<Key, Value>(
|
||||
valueColumnAllocator,
|
||||
tableName
|
||||
) {
|
||||
private val onNewValueChannel = BroadcastChannel<Pair<Key, Value>>(Channel.BUFFERED)
|
||||
private val onValueRemovedChannel = BroadcastChannel<Key>(Channel.BUFFERED)
|
||||
private val _onNewValue = MutableSharedFlow<Pair<Key, Value>>(Channel.BUFFERED)
|
||||
private val _onValueRemoved = MutableSharedFlow<Key>(Channel.BUFFERED)
|
||||
|
||||
override val onNewValue: Flow<Pair<Key, Value>> = onNewValueChannel.asFlow()
|
||||
override val onValueRemoved: Flow<Key> = onValueRemovedChannel.asFlow()
|
||||
override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow()
|
||||
override val onValueRemoved: Flow<Key> = _onValueRemoved.asSharedFlow()
|
||||
|
||||
override suspend fun set(k: Key, v: Value) {
|
||||
override suspend fun set(toSet: Map<Key, Value>) {
|
||||
transaction(database) {
|
||||
if (select { keyColumn.eq(k) }.limit(1).any()) {
|
||||
update({ keyColumn.eq(k) }) {
|
||||
it[valueColumn] = v
|
||||
}
|
||||
} else {
|
||||
insert {
|
||||
it[keyColumn] = k
|
||||
it[valueColumn] = v
|
||||
toSet.mapNotNull { (k, v) ->
|
||||
if (update({ keyColumn.eq(k) }) { it[valueColumn] = v } > 0) {
|
||||
k to v
|
||||
} else {
|
||||
val inserted = insert {
|
||||
it[keyColumn] = k
|
||||
it[valueColumn] = v
|
||||
}.getOrNull(keyColumn) != null
|
||||
if (inserted) {
|
||||
k to v
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}.forEach {
|
||||
_onNewValue.emit(it)
|
||||
}
|
||||
onNewValueChannel.send(k to v)
|
||||
}
|
||||
|
||||
override suspend fun unset(k: Key) {
|
||||
override suspend fun unset(toUnset: List<Key>) {
|
||||
transaction(database) {
|
||||
deleteWhere { keyColumn.eq(k) }
|
||||
toUnset.mapNotNull {
|
||||
if (deleteWhere { keyColumn.eq(it) } > 0) {
|
||||
it
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}.forEach {
|
||||
_onValueRemoved.emit(it)
|
||||
}
|
||||
onValueRemovedChannel.send(k)
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("ExposedKeyValueRepo", "dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo"))
|
||||
typealias AbstractExposedKeyValueRepo<Key, Value> = ExposedKeyValueRepo<Key, Value>
|
||||
|
@@ -2,7 +2,8 @@ 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.exposed.*
|
||||
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
|
||||
import dev.inmo.micro_utils.repos.exposed.ExposedRepo
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
@@ -38,6 +39,3 @@ open class ExposedReadKeyValueRepo<Key, Value>(
|
||||
}
|
||||
}.createPaginationResult(pagination, count())
|
||||
}
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("ExposedReadKeyValueRepo", "dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedReadKeyValueRepo"))
|
||||
typealias AbstractExposedReadKeyValueRepo<Key, Value> = ExposedReadKeyValueRepo<Key, Value>
|
||||
|
@@ -1,10 +1,8 @@
|
||||
package dev.inmo.micro_utils.repos.exposed.onetomany
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.BroadcastFlow
|
||||
import dev.inmo.micro_utils.repos.OneToManyKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
|
||||
import dev.inmo.micro_utils.repos.exposed.initTable
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.*
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
@@ -19,40 +17,48 @@ open class ExposedOneToManyKeyValueRepo<Key, Value>(
|
||||
valueColumnAllocator,
|
||||
tableName
|
||||
) {
|
||||
protected val _onNewValue: BroadcastFlow<Pair<Key, Value>> = BroadcastFlow()
|
||||
protected val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
|
||||
override val onNewValue: Flow<Pair<Key, Value>>
|
||||
get() = _onNewValue
|
||||
protected val _onValueRemoved: BroadcastFlow<Pair<Key, Value>> = BroadcastFlow()
|
||||
protected val _onValueRemoved: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
|
||||
override val onValueRemoved: Flow<Pair<Key, Value>>
|
||||
get() = _onValueRemoved
|
||||
protected val _onDataCleared: BroadcastFlow<Key> = BroadcastFlow()
|
||||
protected val _onDataCleared: MutableSharedFlow<Key> = MutableSharedFlow()
|
||||
override val onDataCleared: Flow<Key>
|
||||
get() = _onDataCleared
|
||||
|
||||
override suspend fun add(k: Key, v: Value) {
|
||||
override suspend fun add(toAdd: Map<Key, List<Value>>) {
|
||||
transaction(database) {
|
||||
insert {
|
||||
it[keyColumn] = k
|
||||
it[valueColumn] = v
|
||||
toAdd.keys.flatMap { k ->
|
||||
toAdd[k] ?.mapNotNull { v ->
|
||||
insertIgnore {
|
||||
it[keyColumn] = k
|
||||
it[valueColumn] = v
|
||||
}.getOrNull(keyColumn) ?.let { k to v }
|
||||
} ?: emptyList()
|
||||
}
|
||||
}.also { _onNewValue.send(k to v) }
|
||||
}.forEach { _onNewValue.emit(it) }
|
||||
}
|
||||
|
||||
override suspend fun remove(k: Key, v: Value) {
|
||||
override suspend fun remove(toRemove: Map<Key, List<Value>>) {
|
||||
transaction(database) {
|
||||
deleteWhere { keyColumn.eq(k).and(valueColumn.eq(v)) }
|
||||
}.also { _onValueRemoved.send(k to v) }
|
||||
toRemove.keys.flatMap { k ->
|
||||
toRemove[k] ?.mapNotNull { v ->
|
||||
if (deleteIgnoreWhere { keyColumn.eq(k).and(valueColumn.eq(v)) } > 0 ) {
|
||||
k to v
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} ?: emptyList()
|
||||
}
|
||||
}.forEach {
|
||||
_onValueRemoved.emit(it)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun clear(k: Key) {
|
||||
transaction(database) {
|
||||
deleteWhere { keyColumn.eq(k) }
|
||||
}.also { _onDataCleared.send(k) }
|
||||
}.also { _onDataCleared.emit(k) }
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("ExposedOneToManyKeyValueRepo", "dev.inmo.micro_utils.repos.exposed.onetomany.ExposedOneToManyKeyValueRepo"))
|
||||
typealias AbstractOneToManyExposedKeyValueRepo<Key, Value> = ExposedOneToManyKeyValueRepo<Key, Value>
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("ExposedOneToManyKeyValueRepo", "dev.inmo.micro_utils.repos.exposed.onetomany.ExposedOneToManyKeyValueRepo"))
|
||||
typealias AbstractExposedOneToManyKeyValueRepo<Key, Value> = ExposedOneToManyKeyValueRepo<Key, Value>
|
||||
|
@@ -47,9 +47,3 @@ open class ExposedReadOneToManyKeyValueRepo<Key, Value>(
|
||||
select { keyColumn.eq(k).and(valueColumn.eq(v)) }.limit(1).any()
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("ExposedReadOneToManyKeyValueRepo", "dev.inmo.micro_utils.repos.exposed.onetomany.ExposedReadOneToManyKeyValueRepo"))
|
||||
typealias AbstractOneToManyExposedReadKeyValueRepo<Key, Value> = ExposedReadOneToManyKeyValueRepo<Key, Value>
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("ExposedReadOneToManyKeyValueRepo", "dev.inmo.micro_utils.repos.exposed.onetomany.ExposedReadOneToManyKeyValueRepo"))
|
||||
typealias AbstractExposedReadOneToManyKeyValueRepo<Key, Value> = ExposedReadOneToManyKeyValueRepo<Key, Value>
|
||||
|
@@ -1,8 +1,7 @@
|
||||
package dev.inmo.micro_utils.repos
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.BroadcastFlow
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
class ReadMapCRUDRepo<ObjectType, IdType>(
|
||||
private val map: Map<IdType, ObjectType> = emptyMap()
|
||||
@@ -26,15 +25,12 @@ class ReadMapCRUDRepo<ObjectType, IdType>(
|
||||
abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||
private val map: MutableMap<IdType, ObjectType> = mutableMapOf()
|
||||
) : WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> {
|
||||
private val _newObjectsFlow: BroadcastFlow<ObjectType> = BroadcastFlow()
|
||||
override val newObjectsFlow: Flow<ObjectType>
|
||||
get() = _newObjectsFlow
|
||||
private val _updatedObjectsFlow: BroadcastFlow<ObjectType> = BroadcastFlow()
|
||||
override val updatedObjectsFlow: Flow<ObjectType>
|
||||
get() = _updatedObjectsFlow
|
||||
private val _deletedObjectsIdsFlow: BroadcastFlow<IdType> = BroadcastFlow()
|
||||
override val deletedObjectsIdsFlow: Flow<IdType>
|
||||
get() = _deletedObjectsIdsFlow
|
||||
private val _newObjectsFlow: MutableSharedFlow<ObjectType> = MutableSharedFlow()
|
||||
override val newObjectsFlow: Flow<ObjectType> = _newObjectsFlow.asSharedFlow()
|
||||
private val _updatedObjectsFlow: MutableSharedFlow<ObjectType> = MutableSharedFlow()
|
||||
override val updatedObjectsFlow: Flow<ObjectType> = _updatedObjectsFlow.asSharedFlow()
|
||||
private val _deletedObjectsIdsFlow: MutableSharedFlow<IdType> = MutableSharedFlow()
|
||||
override val deletedObjectsIdsFlow: Flow<IdType> = _deletedObjectsIdsFlow.asSharedFlow()
|
||||
|
||||
protected abstract suspend fun updateObject(newValue: InputValueType, id: IdType, old: ObjectType): ObjectType
|
||||
protected abstract suspend fun createObject(newValue: InputValueType): Pair<IdType, ObjectType>
|
||||
@@ -44,7 +40,7 @@ abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||
val (id, newObject) = createObject(it)
|
||||
map[id] = newObject
|
||||
newObject.also { _ ->
|
||||
_newObjectsFlow.send(newObject)
|
||||
_newObjectsFlow.emit(newObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,7 +50,7 @@ abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||
|
||||
return newValue.also {
|
||||
map[id] = it
|
||||
_updatedObjectsFlow.send(it)
|
||||
_updatedObjectsFlow.emit(it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +60,7 @@ abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||
|
||||
override suspend fun deleteById(ids: List<IdType>) {
|
||||
ids.forEach {
|
||||
map.remove(it) ?.also { _ -> _deletedObjectsIdsFlow.send(it) }
|
||||
map.remove(it) ?.also { _ -> _deletedObjectsIdsFlow.emit(it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,11 @@
|
||||
package dev.inmo.micro_utils.repos
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.BroadcastFlow
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
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 kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
||||
class ReadMapKeyValueRepo<Key, Value>(
|
||||
private val map: Map<Key, Value> = emptyMap()
|
||||
@@ -46,20 +47,22 @@ class ReadMapKeyValueRepo<Key, Value>(
|
||||
class WriteMapKeyValueRepo<Key, Value>(
|
||||
private val map: MutableMap<Key, Value> = mutableMapOf()
|
||||
) : WriteStandardKeyValueRepo<Key, Value> {
|
||||
private val _onNewValue: BroadcastFlow<Pair<Key, Value>> = BroadcastFlow()
|
||||
private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
|
||||
override val onNewValue: Flow<Pair<Key, Value>>
|
||||
get() = _onNewValue
|
||||
private val _onValueRemoved: BroadcastFlow<Key> = BroadcastFlow()
|
||||
private val _onValueRemoved: MutableSharedFlow<Key> = MutableSharedFlow()
|
||||
override val onValueRemoved: Flow<Key>
|
||||
get() = _onValueRemoved
|
||||
|
||||
override suspend fun set(k: Key, v: Value) {
|
||||
map[k] = v
|
||||
_onNewValue.send(k to v)
|
||||
override suspend fun set(toSet: Map<Key, Value>) {
|
||||
map.putAll(toSet)
|
||||
toSet.forEach { (k, v) -> _onNewValue.emit(k to v) }
|
||||
}
|
||||
|
||||
override suspend fun unset(k: Key) {
|
||||
map.remove(k) ?.also { _onValueRemoved.send(k) }
|
||||
override suspend fun unset(toUnset: List<Key>) {
|
||||
toUnset.forEach { k ->
|
||||
map.remove(k) ?.also { _ -> _onValueRemoved.emit(k) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,9 @@
|
||||
package dev.inmo.micro_utils.repos
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.BroadcastFlow
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.pagination.utils.paginate
|
||||
import dev.inmo.micro_utils.pagination.utils.reverse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
class MapReadOneToManyKeyValueRepo<Key, Value>(
|
||||
private val map: Map<Key, List<Value>> = emptyMap()
|
||||
@@ -45,27 +44,35 @@ class MapReadOneToManyKeyValueRepo<Key, Value>(
|
||||
class MapWriteOneToManyKeyValueRepo<Key, Value>(
|
||||
private val map: MutableMap<Key, MutableList<Value>> = mutableMapOf()
|
||||
) : WriteOneToManyKeyValueRepo<Key, Value> {
|
||||
private val _onNewValue: BroadcastFlow<Pair<Key, Value>> = BroadcastFlow()
|
||||
override val onNewValue: Flow<Pair<Key, Value>>
|
||||
get() = _onNewValue
|
||||
private val _onValueRemoved: BroadcastFlow<Pair<Key, Value>> = BroadcastFlow()
|
||||
override val onValueRemoved: Flow<Pair<Key, Value>>
|
||||
get() = _onValueRemoved
|
||||
private val _onDataCleared: BroadcastFlow<Key> = BroadcastFlow()
|
||||
override val onDataCleared: Flow<Key>
|
||||
get() = _onDataCleared
|
||||
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()
|
||||
override val onValueRemoved: Flow<Pair<Key, Value>> = _onValueRemoved.asSharedFlow()
|
||||
private val _onDataCleared: MutableSharedFlow<Key> = MutableSharedFlow()
|
||||
override val onDataCleared: Flow<Key> = _onDataCleared.asSharedFlow()
|
||||
|
||||
override suspend fun add(k: Key, v: Value) {
|
||||
map.getOrPut(k) { mutableListOf() }.add(v)
|
||||
_onNewValue.send(k to v)
|
||||
override suspend fun add(toAdd: Map<Key, List<Value>>) {
|
||||
toAdd.keys.forEach { k ->
|
||||
if (map.getOrPut(k) { mutableListOf() }.addAll(toAdd[k] ?: return@forEach)) {
|
||||
toAdd[k] ?.forEach { v ->
|
||||
_onNewValue.emit(k to v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun remove(k: Key, v: Value) {
|
||||
map[k] ?.remove(v) ?.also { _onValueRemoved.send(k to v) }
|
||||
override suspend fun remove(toRemove: Map<Key, List<Value>>) {
|
||||
toRemove.keys.forEach { k ->
|
||||
if (map[k] ?.removeAll(toRemove[k] ?: return@forEach) == true) {
|
||||
toRemove[k] ?.forEach { v ->
|
||||
_onValueRemoved.emit(k to v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun clear(k: Key) {
|
||||
map.remove(k) ?.also { _onDataCleared.send(k) }
|
||||
map.remove(k) ?.also { _onDataCleared.emit(k) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,9 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.client.crud
|
||||
import dev.inmo.micro_utils.ktor.client.encodeUrlQueryValue
|
||||
import dev.inmo.micro_utils.ktor.client.uniget
|
||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
import dev.inmo.micro_utils.pagination.asUrlQueryParts
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||
import io.ktor.client.HttpClient
|
||||
|
@@ -1,8 +1,6 @@
|
||||
package dev.inmo.micro_utils.repos.ktor.client.crud
|
||||
|
||||
import dev.inmo.micro_utils.ktor.client.BodyPair
|
||||
import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
|
||||
import dev.inmo.micro_utils.ktor.client.unipost
|
||||
import dev.inmo.micro_utils.ktor.client.*
|
||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
||||
import dev.inmo.micro_utils.repos.UpdatedValuePair
|
||||
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
|
||||
|
@@ -3,12 +3,10 @@ package dev.inmo.micro_utils.repos.ktor.client.key_value
|
||||
import dev.inmo.micro_utils.ktor.client.encodeUrlQueryValue
|
||||
import dev.inmo.micro_utils.ktor.client.uniget
|
||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
import dev.inmo.micro_utils.pagination.asUrlQueryParts
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.HttpClient
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
|
||||
@@ -71,6 +69,3 @@ class KtorReadStandardKeyValueRepo<Key, Value> (
|
||||
Long.serializer()
|
||||
)
|
||||
}
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("KtorReadStandardKeyValueRepo", "dev.inmo.micro_utils.repos.ktor.client.key_value.KtorReadStandardKeyValueRepo"))
|
||||
typealias KtorStandartReadKeyValueRepo<Key, Value> = KtorReadStandardKeyValueRepo<Key, Value>
|
||||
|
@@ -1,9 +1,7 @@
|
||||
package dev.inmo.micro_utils.repos.ktor.client.key_value
|
||||
|
||||
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
|
||||
import io.ktor.client.*
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import io.ktor.client.HttpClient
|
||||
import kotlinx.serialization.KSerializer
|
||||
|
||||
class KtorStandartKeyValueRepo<K, V> (
|
||||
|
@@ -1,16 +1,13 @@
|
||||
package dev.inmo.micro_utils.repos.ktor.client.key_value
|
||||
|
||||
import dev.inmo.micro_utils.ktor.client.BodyPair
|
||||
import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
|
||||
import dev.inmo.micro_utils.ktor.client.unipost
|
||||
import dev.inmo.micro_utils.ktor.client.*
|
||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
||||
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.HttpClient
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.PairSerializer
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import kotlinx.serialization.builtins.*
|
||||
|
||||
class KtorWriteStandardKeyValueRepo<K, V> (
|
||||
private var baseUrl: String,
|
||||
@@ -18,6 +15,8 @@ class KtorWriteStandardKeyValueRepo<K, V> (
|
||||
private var keySerializer: KSerializer<K>,
|
||||
private var valueSerializer: KSerializer<V>,
|
||||
) : WriteStandardKeyValueRepo<K, V> {
|
||||
private val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer)
|
||||
private val keysListSerializer = ListSerializer(keySerializer)
|
||||
override val onNewValue: Flow<Pair<K, V>> = client.createStandardWebsocketFlow(
|
||||
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||
deserializer = PairSerializer(keySerializer, valueSerializer)
|
||||
@@ -28,24 +27,21 @@ class KtorWriteStandardKeyValueRepo<K, V> (
|
||||
deserializer = keySerializer
|
||||
)
|
||||
|
||||
override suspend fun set(k: K, v: V) = client.unipost(
|
||||
override suspend fun set(toSet: Map<K, V>) = client.unipost(
|
||||
buildStandardUrl(
|
||||
baseUrl,
|
||||
setRoute
|
||||
),
|
||||
BodyPair(KeyValuePostObject.serializer(keySerializer, valueSerializer), KeyValuePostObject(k, v)),
|
||||
BodyPair(keyValueMapSerializer, toSet),
|
||||
Unit.serializer()
|
||||
)
|
||||
|
||||
override suspend fun unset(k: K) = client.unipost(
|
||||
override suspend fun unset(toUnset: List<K>) = client.unipost(
|
||||
buildStandardUrl(
|
||||
baseUrl,
|
||||
unsetRoute,
|
||||
),
|
||||
BodyPair(keySerializer, k),
|
||||
BodyPair(keysListSerializer, toUnset),
|
||||
Unit.serializer()
|
||||
)
|
||||
}
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("KtorWriteStandardKeyValueRepo", "dev.inmo.micro_utils.repos.ktor.client.key_value.KtorWriteStandardKeyValueRepo"))
|
||||
typealias KtorStandartWriteKeyValueRepo<K, V> = KtorWriteStandardKeyValueRepo<K, V>
|
||||
|
@@ -1,8 +1,6 @@
|
||||
package dev.inmo.micro_utils.repos.ktor.client.one_to_many
|
||||
|
||||
import dev.inmo.micro_utils.repos.OneToManyKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import io.ktor.client.HttpClient
|
||||
import kotlinx.serialization.KSerializer
|
||||
|
||||
|
@@ -3,9 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.client.one_to_many
|
||||
import dev.inmo.micro_utils.ktor.client.encodeUrlQueryValue
|
||||
import dev.inmo.micro_utils.ktor.client.uniget
|
||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
import dev.inmo.micro_utils.pagination.asUrlQueryParts
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
|
||||
import io.ktor.client.HttpClient
|
||||
|
@@ -1,16 +1,13 @@
|
||||
package dev.inmo.micro_utils.repos.ktor.client.one_to_many
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.broadcastStateFlow
|
||||
import dev.inmo.micro_utils.ktor.client.*
|
||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
||||
import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
|
||||
import io.ktor.client.HttpClient
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.PairSerializer
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import kotlinx.serialization.builtins.*
|
||||
|
||||
class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
||||
private val baseUrl: String,
|
||||
@@ -19,6 +16,7 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
||||
private val valueSerializer: KSerializer<Value>
|
||||
) : WriteOneToManyKeyValueRepo<Key, Value> {
|
||||
private val keyValueSerializer = PairSerializer(keySerializer, valueSerializer)
|
||||
private val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer))
|
||||
override val onNewValue: Flow<Pair<Key, Value>> = client.createStandardWebsocketFlow(
|
||||
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||
deserializer = keyValueSerializer
|
||||
@@ -32,24 +30,23 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
||||
deserializer = keySerializer
|
||||
)
|
||||
|
||||
override suspend fun add(k: Key, v: Value) = client.unipost(
|
||||
buildStandardUrl(
|
||||
baseUrl,
|
||||
addRoute,
|
||||
),
|
||||
BodyPair(keyValueSerializer, k to v),
|
||||
Unit.serializer(),
|
||||
)
|
||||
|
||||
override suspend fun remove(k: Key, v: Value) = client.unipost(
|
||||
override suspend fun remove(toRemove: Map<Key, List<Value>>) = client.unipost(
|
||||
buildStandardUrl(
|
||||
baseUrl,
|
||||
removeRoute,
|
||||
),
|
||||
BodyPair(keyValueSerializer, k to v),
|
||||
BodyPair(keyValueMapSerializer, toRemove),
|
||||
Unit.serializer(),
|
||||
)
|
||||
|
||||
override suspend fun add(toAdd: Map<Key, List<Value>>) = client.unipost(
|
||||
buildStandardUrl(
|
||||
baseUrl,
|
||||
clearRoute,
|
||||
),
|
||||
BodyPair(keyValueMapSerializer, toAdd),
|
||||
Unit.serializer(),
|
||||
)
|
||||
override suspend fun clear(k: Key) = client.unipost(
|
||||
buildStandardUrl(
|
||||
baseUrl,
|
||||
|
@@ -1,8 +1,6 @@
|
||||
package dev.inmo.micro_utils.repos.ktor.server.crud
|
||||
|
||||
import dev.inmo.micro_utils.ktor.server.includeWebsocketHandling
|
||||
import dev.inmo.micro_utils.ktor.server.unianswer
|
||||
import dev.inmo.micro_utils.ktor.server.uniload
|
||||
import dev.inmo.micro_utils.ktor.server.*
|
||||
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
|
||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||
import io.ktor.application.call
|
||||
|
@@ -1,7 +1,8 @@
|
||||
package dev.inmo.micro_utils.repos.ktor.server.key_value
|
||||
|
||||
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
|
||||
import io.ktor.routing.*
|
||||
import io.ktor.routing.Route
|
||||
import io.ktor.routing.route
|
||||
import kotlinx.serialization.KSerializer
|
||||
|
||||
fun <K, V> Route.configureStandartKeyValueRepoRoutes(
|
||||
|
@@ -6,8 +6,9 @@ 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.ktor.common.key_value.*
|
||||
import io.ktor.application.*
|
||||
import io.ktor.routing.*
|
||||
import io.ktor.application.call
|
||||
import io.ktor.routing.Route
|
||||
import io.ktor.routing.get
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
|
||||
|
@@ -1,19 +1,21 @@
|
||||
package dev.inmo.micro_utils.repos.ktor.server.key_value
|
||||
|
||||
import dev.inmo.micro_utils.ktor.server.includeWebsocketHandling
|
||||
import dev.inmo.micro_utils.ktor.server.uniload
|
||||
import dev.inmo.micro_utils.ktor.server.*
|
||||
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
||||
import io.ktor.application.*
|
||||
import io.ktor.routing.*
|
||||
import io.ktor.application.call
|
||||
import io.ktor.routing.Route
|
||||
import io.ktor.routing.post
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.PairSerializer
|
||||
import kotlinx.serialization.builtins.*
|
||||
|
||||
fun <K, V> Route.configureWriteStandartKeyValueRepoRoutes (
|
||||
originalRepo: WriteStandardKeyValueRepo<K, V>,
|
||||
keySerializer: KSerializer<K>,
|
||||
valueSerializer: KSerializer<V>,
|
||||
) {
|
||||
val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer)
|
||||
val keysListSerializer = ListSerializer(keySerializer)
|
||||
includeWebsocketHandling(
|
||||
onNewValueRoute,
|
||||
originalRepo.onNewValue,
|
||||
@@ -27,18 +29,16 @@ fun <K, V> Route.configureWriteStandartKeyValueRepoRoutes (
|
||||
)
|
||||
|
||||
post(setRoute) {
|
||||
val (key, value) = call.uniload(
|
||||
KeyValuePostObject.serializer(keySerializer, valueSerializer)
|
||||
val toSet = call.uniload(
|
||||
keyValueMapSerializer
|
||||
)
|
||||
|
||||
originalRepo.set(key, value)
|
||||
call.unianswer(Unit.serializer(), originalRepo.set(toSet))
|
||||
}
|
||||
|
||||
post(unsetRoute) {
|
||||
val key = call.uniload(
|
||||
keySerializer
|
||||
)
|
||||
val toUnset = call.uniload(keysListSerializer)
|
||||
|
||||
originalRepo.unset(key)
|
||||
call.unianswer(Unit.serializer(), originalRepo.unset(toUnset))
|
||||
}
|
||||
}
|
@@ -1,8 +1,6 @@
|
||||
package dev.inmo.micro_utils.repos.ktor.server.one_to_many
|
||||
|
||||
import dev.inmo.micro_utils.ktor.server.decodeUrlQueryValue
|
||||
import dev.inmo.micro_utils.ktor.server.decodeUrlQueryValueOrSendError
|
||||
import dev.inmo.micro_utils.ktor.server.unianswer
|
||||
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
|
||||
|
@@ -7,15 +7,15 @@ import io.ktor.application.call
|
||||
import io.ktor.routing.Route
|
||||
import io.ktor.routing.post
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.PairSerializer
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import kotlinx.serialization.builtins.*
|
||||
|
||||
fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes(
|
||||
originalRepo: WriteOneToManyKeyValueRepo<Key, Value>,
|
||||
keySerializer: KSerializer<Key>,
|
||||
valueSealizer: KSerializer<Value>,
|
||||
valueSerializer: KSerializer<Value>,
|
||||
) {
|
||||
val keyValueSerializer = PairSerializer(keySerializer, valueSealizer)
|
||||
val keyValueSerializer = PairSerializer(keySerializer, valueSerializer)
|
||||
val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer))
|
||||
|
||||
includeWebsocketHandling(
|
||||
onNewValueRoute,
|
||||
@@ -34,24 +34,22 @@ fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes(
|
||||
)
|
||||
|
||||
post(addRoute) {
|
||||
val obj = call.uniload(
|
||||
keyValueSerializer
|
||||
)
|
||||
val obj = call.uniload(keyValueMapSerializer)
|
||||
|
||||
call.unianswer(
|
||||
Unit.serializer(),
|
||||
originalRepo.add(obj.first, obj.second)
|
||||
originalRepo.add(obj)
|
||||
)
|
||||
}
|
||||
|
||||
post(removeRoute) {
|
||||
val obj = call.uniload(
|
||||
keyValueSerializer
|
||||
keyValueMapSerializer
|
||||
)
|
||||
|
||||
call.unianswer(
|
||||
Unit.serializer(),
|
||||
originalRepo.remove(obj.first, obj.second),
|
||||
originalRepo.remove(obj),
|
||||
)
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user