mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-17 22:39:25 +00:00
Compare commits
71 Commits
Author | SHA1 | Date | |
---|---|---|---|
e38094df58 | |||
c25e3f5867 | |||
f78e81d175 | |||
3837ae237d | |||
2b6ef8b4ff | |||
6cc0eefb3e | |||
ab11e28bf7 | |||
26d5f5a5f5 | |||
74ae91cba6 | |||
70509c7edd | |||
5a69bd6c63 | |||
091bb1394f | |||
b82c3864a0 | |||
49ee38a936 | |||
c201866c51 | |||
023f841fb5 | |||
76102e9ab3 | |||
b2fc5e2a4d | |||
55aacb8753 | |||
8702846216 | |||
3347a6d189 | |||
47b3b42949 | |||
e985631621 | |||
e15034bfa4 | |||
e5dbcd25dd | |||
3714c02c12 | |||
fa636b4146 | |||
3d825aebc3 | |||
629884a396 | |||
e7a0fa4e8f | |||
1a41f37a9d | |||
07a65e0bb5 | |||
615f7f99c3 | |||
3de5558ed4 | |||
6bbe3a271f | |||
8bee29f683 | |||
c40f0fdcb9 | |||
30d1453a12 | |||
75fa88b00d | |||
0f817ad212 | |||
d7b46ae0d4 | |||
b6be14ecca | |||
33dbfc6f69 | |||
fcacdcd544 | |||
dd2fc5a86f | |||
0f8a6f6bde | |||
1efd94181d | |||
71ff0232aa | |||
63921cd984 | |||
051e03bed3 | |||
a051394f4f | |||
b872babe45 | |||
5a9cabc4bd | |||
3ba630684a | |||
498cd12f94 | |||
062848f2e4 | |||
d4b4547718 | |||
22cd440dd7 | |||
6fc64526d4 | |||
08075dfafe | |||
efcb25622e | |||
5ebf29d1fb | |||
b7d0ce3c97 | |||
e20929aec4 | |||
f74167cc65 | |||
c55cd5342e | |||
237d89d611 | |||
aff9b52f1c | |||
d8cc6ed06e | |||
dffafa54c3 | |||
776a3af497 |
20
.travis.yml
20
.travis.yml
@@ -1,13 +1,27 @@
|
|||||||
language: java
|
language: android
|
||||||
install: true
|
install: true
|
||||||
|
|
||||||
os: linux
|
os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
jdk: oraclejdk8
|
jdk: oraclejdk8
|
||||||
|
|
||||||
|
android:
|
||||||
|
components:
|
||||||
|
- tools
|
||||||
|
- platform-tools
|
||||||
|
- build-tools-30.0.2
|
||||||
|
- android-30
|
||||||
|
- add-on
|
||||||
|
- extra
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- yes | /usr/local/android-sdk/tools/bin/sdkmanager "build-tools;30.0.2"
|
||||||
|
- yes | /usr/local/android-sdk/tools/bin/sdkmanager "platforms;android-30"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- stage: build
|
- stage: build
|
||||||
script: ./gradlew build -s -x jvmTest -x jsIrTest -x jsIrBrowserTest -x jsIrNodeTest -x jsLegacyTest -x jsLegacyBrowserTest -x jsLegacyNodeTest
|
script: ./gradlew build -s -x jvmTest -x jsIrTest -x jsIrBrowserTest -x jsIrNodeTest -x jsLegacyTest -x jsLegacyBrowserTest -x jsLegacyNodeTest
|
||||||
- state: test
|
# Tests are temporarily disabled on public travis due to the problems of launching
|
||||||
script: ./gradlew allTests
|
# - state: test
|
||||||
|
# script: ./gradlew allTests
|
||||||
|
113
CHANGELOG.md
113
CHANGELOG.md
@@ -1,5 +1,116 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.4.8
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Coroutines`: `1.4.1` -> `1.4.2`
|
||||||
|
* `UUID`: `0.2.2` -> `0.2.3`
|
||||||
|
* `Pagination`
|
||||||
|
* Add `PaginatedIterable` and `PaginatedIterator`
|
||||||
|
|
||||||
|
## 0.4.7
|
||||||
|
|
||||||
|
* `Ktor`
|
||||||
|
* `Client`
|
||||||
|
* New class `UnifiedRequester`
|
||||||
|
* `Server`
|
||||||
|
* New class `UnifiedRouter`
|
||||||
|
* `Repos`
|
||||||
|
* `Ktor`
|
||||||
|
* `Client`
|
||||||
|
* Rewriting of all clients on new `UnifiedRequester`
|
||||||
|
* `Server`
|
||||||
|
* Rewriting of all clients on new `UnifiedRouter`
|
||||||
|
|
||||||
|
## 0.4.6
|
||||||
|
|
||||||
|
* `Common`
|
||||||
|
* New annotation `Warning` has been added
|
||||||
|
* `Pagination`
|
||||||
|
* `Common`
|
||||||
|
* `Pagination` got new extension: `Pagination#isFirstPage`
|
||||||
|
* `Coroutines`:
|
||||||
|
* New extension `FlowCollector#invoke` has been added
|
||||||
|
* `Repos`
|
||||||
|
* `Common`
|
||||||
|
* `JVM` (and `Android` since `Android API 26`):
|
||||||
|
* `FileStandardKeyValueRepo` has been added
|
||||||
|
* Add several `typealias`es for each type of repos
|
||||||
|
|
||||||
|
## 0.4.5
|
||||||
|
|
||||||
|
* `Android`
|
||||||
|
* `Alerts`
|
||||||
|
* `Common`
|
||||||
|
* Project has been created
|
||||||
|
* `RecyclerView`
|
||||||
|
* Project has been created
|
||||||
|
* `Common`
|
||||||
|
* Annotation `PreviewFeature` has been added
|
||||||
|
* `Android`
|
||||||
|
* Added tools to work with visibility in more comfortable way
|
||||||
|
* Added tools to work with disabled/enabled state in more comfortable way
|
||||||
|
* Added tools to work with expanded/collapsed state in more comfortable way (in preview mode)
|
||||||
|
|
||||||
|
## 0.4.4
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Klock`: `1.12.1` -> `2.0.0`
|
||||||
|
* `Commons`:
|
||||||
|
* Update left items functionality to include work with `GridLayoutManager`
|
||||||
|
* `Repos`:
|
||||||
|
* Add interface `VersionsRepo`
|
||||||
|
* Add default realization of `VersionsRepo` named `StandardVersionsRepo` which use `StandardVersionsRepoProxy`
|
||||||
|
to get access to some end-store
|
||||||
|
* Add default realization of `StandardVersionsRepoProxy` based on `KeyValue` repos
|
||||||
|
* Add realizations of `StandardVersionsRepoProxy` for exposed and android (`SQL` and `SharedPreferences`)
|
||||||
|
* `Commons`:
|
||||||
|
* In Android fully reworked transactions functions
|
||||||
|
* Now `DatabaseCoroutineContext` is a shortcut for `Dispatchers.IO`
|
||||||
|
|
||||||
|
## 0.4.3
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Kotlin`: `1.4.10` -> `1.4.20`
|
||||||
|
* `Common`:
|
||||||
|
* Two new extensions for Android:
|
||||||
|
* `Resources#getSp`
|
||||||
|
* `Resources#getDp`
|
||||||
|
|
||||||
|
## 0.4.2
|
||||||
|
|
||||||
|
* `Repos`:
|
||||||
|
* Add `WriteOneToManyKeyValueRepo#set` function and extensions
|
||||||
|
|
||||||
|
## 0.4.1
|
||||||
|
|
||||||
|
* `Repos`:
|
||||||
|
* Fixed error in `ExposedKeyValueRepo` related to negative size of shared flow
|
||||||
|
* Fixed error in `ExposedKeyValueRepo` related to avoiding of table initiation
|
||||||
|
|
||||||
|
## 0.4.0
|
||||||
|
|
||||||
|
* `Repos`:
|
||||||
|
* `ReadOneToManyKeyValueRepo` got `keys` method with value parameter
|
||||||
|
* All implementations inside of this library has been updated
|
||||||
|
* `ReadStandardKeyValueRepo` got `keys` method with value parameter
|
||||||
|
* All implementations inside of this library has been updated
|
||||||
|
* New extensions `withMapper`
|
||||||
|
|
||||||
|
## 0.3.3
|
||||||
|
|
||||||
|
* `Coroutines`:
|
||||||
|
* New extension `Flow<T>#plus`
|
||||||
|
|
||||||
|
## 0.3.2
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Coroutines`: `1.4.1` -> `1.4.2`
|
||||||
|
* `Repos`:
|
||||||
|
* `Common`:
|
||||||
|
* New inline function `mapper` for simplier creating of `MapperRepo` objects
|
||||||
|
* Extensions `withMapper` for keyvalue repos and onetomany repos
|
||||||
|
|
||||||
## 0.3.1
|
## 0.3.1
|
||||||
|
|
||||||
**ANDROID PACKAGES**
|
**ANDROID PACKAGES**
|
||||||
@@ -201,4 +312,4 @@ All deprecations has been removed
|
|||||||
|
|
||||||
## 0.1.0
|
## 0.1.0
|
||||||
|
|
||||||
Inited :)
|
Inited :)
|
||||||
|
17
android/alerts/common/build.gradle
Normal file
17
android/alerts/common/build.gradle
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
id "com.android.library"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppAndroidProjectPresetPath"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
androidMain {
|
||||||
|
dependencies {
|
||||||
|
api "androidx.appcompat:appcompat-resources:$appcompat_version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
android/alerts/common/src/main/AndroidManifest.xml
Normal file
1
android/alerts/common/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.micro_utils.android.alerts.common"/>
|
@@ -0,0 +1,55 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE", "unused")
|
||||||
|
|
||||||
|
package dev.inmo.micro_utils.android.alerts.common
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
|
|
||||||
|
typealias AlertDialogCallback = (DialogInterface) -> Unit
|
||||||
|
|
||||||
|
inline fun Context.createAlertDialogTemplate(
|
||||||
|
title: String? = null,
|
||||||
|
positivePair: Pair<String, AlertDialogCallback?>? = null,
|
||||||
|
neutralPair: Pair<String, AlertDialogCallback?>? = null,
|
||||||
|
negativePair: Pair<String, AlertDialogCallback?>? = null
|
||||||
|
): AlertDialog.Builder {
|
||||||
|
val builder = AlertDialog.Builder(this)
|
||||||
|
|
||||||
|
title ?.let {
|
||||||
|
builder.setTitle(title)
|
||||||
|
}
|
||||||
|
|
||||||
|
positivePair ?. let {
|
||||||
|
builder.setPositiveButton(it.first) { di, _ -> it.second ?. invoke(di) }
|
||||||
|
}
|
||||||
|
negativePair ?. let {
|
||||||
|
builder.setNegativeButton(it.first) { di, _ -> it.second ?. invoke(di) }
|
||||||
|
}
|
||||||
|
neutralPair ?. let {
|
||||||
|
builder.setNeutralButton(it.first) { di, _ -> it.second ?. invoke(di) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun Context.createAlertDialogTemplateWithResources(
|
||||||
|
title: Int? = null,
|
||||||
|
positivePair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
neutralPair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
negativePair: Pair<Int, AlertDialogCallback?>? = null
|
||||||
|
): AlertDialog.Builder = createAlertDialogTemplate(
|
||||||
|
title ?.let { getString(it) },
|
||||||
|
positivePair ?.let { getString(it.first) to it.second },
|
||||||
|
neutralPair ?.let { getString(it.first) to it.second },
|
||||||
|
negativePair ?.let { getString(it.first) to it.second }
|
||||||
|
)
|
||||||
|
|
||||||
|
inline fun AlertDialog.setDismissChecker(noinline checker: () -> Boolean) : AlertDialog {
|
||||||
|
setOnDismissListener {
|
||||||
|
if (!checker()) {
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE", "unused")
|
||||||
|
|
||||||
|
package dev.inmo.micro_utils.android.alerts.common
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
inline fun <T: View> Context.createCustomViewAlertDialog(
|
||||||
|
title: String? = null,
|
||||||
|
positivePair: Pair<String, AlertDialogCallback?>? = null,
|
||||||
|
neutralPair: Pair<String, AlertDialogCallback?>? = null,
|
||||||
|
negativePair: Pair<String, AlertDialogCallback?>? = null,
|
||||||
|
show: Boolean = true,
|
||||||
|
viewCreator: (Context) -> T
|
||||||
|
): AlertDialog = createAlertDialogTemplate(
|
||||||
|
title, positivePair, neutralPair, negativePair
|
||||||
|
).apply {
|
||||||
|
setView(viewCreator(this@createCustomViewAlertDialog))
|
||||||
|
}.create().apply {
|
||||||
|
if (show) show()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T: View> Context.createCustomViewAlertDialogWithResources(
|
||||||
|
title: Int? = null,
|
||||||
|
positivePair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
neutralPair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
negativePair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
show: Boolean = true,
|
||||||
|
viewCreator: (Context) -> T
|
||||||
|
): AlertDialog = createCustomViewAlertDialog(
|
||||||
|
title ?.let { getString(it) },
|
||||||
|
positivePair ?.let { getString(it.first) to it.second },
|
||||||
|
neutralPair ?.let { getString(it.first) to it.second },
|
||||||
|
negativePair ?.let { getString(it.first) to it.second },
|
||||||
|
show,
|
||||||
|
viewCreator
|
||||||
|
)
|
@@ -0,0 +1,45 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE", "unused")
|
||||||
|
|
||||||
|
package dev.inmo.micro_utils.android.alerts.common
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
|
||||||
|
inline fun Context.createSimpleTextAlertDialog(
|
||||||
|
text: String,
|
||||||
|
title: String? = null,
|
||||||
|
positivePair: Pair<String, AlertDialogCallback?>? = null,
|
||||||
|
neutralPair: Pair<String, AlertDialogCallback?>? = null,
|
||||||
|
negativePair: Pair<String, AlertDialogCallback?>? = null,
|
||||||
|
show: Boolean = true
|
||||||
|
): AlertDialog = createAlertDialogTemplate(
|
||||||
|
title,
|
||||||
|
positivePair,
|
||||||
|
neutralPair,
|
||||||
|
negativePair
|
||||||
|
).apply {
|
||||||
|
setMessage(text)
|
||||||
|
}.create().apply {
|
||||||
|
if (show) {
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun Context.createSimpleTextAlertDialog(
|
||||||
|
@StringRes
|
||||||
|
text: Int,
|
||||||
|
@StringRes
|
||||||
|
title: Int? = null,
|
||||||
|
positivePair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
neutralPair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
negativePair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
show: Boolean = true
|
||||||
|
): AlertDialog = createSimpleTextAlertDialog(
|
||||||
|
getString(text),
|
||||||
|
title ?.let { getString(it) },
|
||||||
|
positivePair ?.let { getString(it.first) to it.second },
|
||||||
|
neutralPair ?.let { getString(it.first) to it.second },
|
||||||
|
negativePair ?.let { getString(it.first) to it.second },
|
||||||
|
show
|
||||||
|
)
|
18
android/alerts/recyclerview/build.gradle
Normal file
18
android/alerts/recyclerview/build.gradle
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
id "com.android.library"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppAndroidProjectPresetPath"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
api internalProject("micro_utils.android.alerts.common")
|
||||||
|
api internalProject("micro_utils.android.recyclerview")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
android/alerts/recyclerview/src/main/AndroidManifest.xml
Normal file
1
android/alerts/recyclerview/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.micro_utils.android.alerts.recyclerview"/>
|
@@ -0,0 +1,65 @@
|
|||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package dev.inmo.micro_utils.android.alerts.recyclerview
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import dev.inmo.micro_utils.android.alerts.common.AlertDialogCallback
|
||||||
|
import dev.inmo.micro_utils.android.recyclerview.*
|
||||||
|
|
||||||
|
data class AlertAction(
|
||||||
|
val title: String,
|
||||||
|
val callback: (DialogInterface) -> Unit
|
||||||
|
)
|
||||||
|
|
||||||
|
private class ActionViewHolder(
|
||||||
|
container: ViewGroup, dialogInterfaceGetter: () -> DialogInterface
|
||||||
|
) : AbstractStandardViewHolder<AlertAction>(container, android.R.layout.simple_list_item_1) {
|
||||||
|
private lateinit var action: AlertAction
|
||||||
|
private val textView: TextView
|
||||||
|
get() = itemView.findViewById(android.R.id.text1)
|
||||||
|
|
||||||
|
init {
|
||||||
|
itemView.setOnClickListener {
|
||||||
|
action.callback(dialogInterfaceGetter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(item: AlertAction) {
|
||||||
|
action = item
|
||||||
|
textView.text = item.title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ActionsRecyclerViewAdapter(
|
||||||
|
data: List<AlertAction>,
|
||||||
|
private val dialogInterfaceGetter: () -> DialogInterface
|
||||||
|
) : RecyclerViewAdapter<AlertAction>(data) {
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractViewHolder<AlertAction> = ActionViewHolder(
|
||||||
|
parent, dialogInterfaceGetter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.createActionsAlertDialog(
|
||||||
|
actions: List<AlertAction>,
|
||||||
|
title: Int? = null,
|
||||||
|
positivePair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
neutralPair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
negativePair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
show: Boolean = true
|
||||||
|
): AlertDialog {
|
||||||
|
lateinit var dialogInterface: DialogInterface
|
||||||
|
|
||||||
|
return createRecyclerViewDialog(
|
||||||
|
title, positivePair, neutralPair, negativePair, show
|
||||||
|
) {
|
||||||
|
ActionsRecyclerViewAdapter(
|
||||||
|
actions
|
||||||
|
) {
|
||||||
|
dialogInterface
|
||||||
|
}
|
||||||
|
}.also { dialogInterface = it }
|
||||||
|
}
|
@@ -0,0 +1,43 @@
|
|||||||
|
package dev.inmo.micro_utils.android.alerts.recyclerview
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import dev.inmo.micro_utils.android.alerts.common.AlertDialogCallback
|
||||||
|
import dev.inmo.micro_utils.android.alerts.common.createCustomViewAlertDialogWithResources
|
||||||
|
|
||||||
|
fun Context.createRecyclerViewDialog(
|
||||||
|
title: Int? = null,
|
||||||
|
positivePair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
neutralPair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
negativePair: Pair<Int, AlertDialogCallback?>? = null,
|
||||||
|
show: Boolean = true,
|
||||||
|
layoutManager: RecyclerView.LayoutManager = LinearLayoutManager(this),
|
||||||
|
marginOfRecyclerView: Int = 8, // dp
|
||||||
|
recyclerViewSetUp: RecyclerView.() -> Unit = {},
|
||||||
|
adapterFactory: () -> RecyclerView.Adapter<*>
|
||||||
|
): AlertDialog {
|
||||||
|
val recyclerView = RecyclerView(this).apply {
|
||||||
|
layoutParams = LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
).apply {
|
||||||
|
setMargins(marginOfRecyclerView, marginOfRecyclerView, marginOfRecyclerView, marginOfRecyclerView)
|
||||||
|
}
|
||||||
|
this.layoutManager = layoutManager
|
||||||
|
adapter = adapterFactory()
|
||||||
|
recyclerViewSetUp()
|
||||||
|
}
|
||||||
|
|
||||||
|
return createCustomViewAlertDialogWithResources(
|
||||||
|
title,
|
||||||
|
positivePair,
|
||||||
|
neutralPair,
|
||||||
|
negativePair,
|
||||||
|
show
|
||||||
|
) {
|
||||||
|
recyclerView
|
||||||
|
}
|
||||||
|
}
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppAndroidProjectPresetPath"
|
apply from: "$mppAndroidProjectPresetPath"
|
||||||
|
@@ -1,14 +1,20 @@
|
|||||||
package dev.inmo.micro_utils.android.recyclerview
|
package dev.inmo.micro_utils.android.recyclerview
|
||||||
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.*
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
private inline fun RecyclerView.LayoutManager.findLastVisibleItemPositionGetter(): (() -> Int)? = when (this) {
|
||||||
|
is LinearLayoutManager -> ::findLastVisibleItemPosition
|
||||||
|
is GridLayoutManager -> ::findLastVisibleItemPosition
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
fun RecyclerView.lastVisibleItemFlow(
|
fun RecyclerView.lastVisibleItemFlow(
|
||||||
completingScope: CoroutineScope
|
completingScope: CoroutineScope
|
||||||
): Flow<Int> {
|
): Flow<Int> {
|
||||||
val lastVisibleElementFun: () -> Int = (layoutManager as? LinearLayoutManager) ?.let { it::findLastVisibleItemPosition } ?: error("Currently supported only linear layout manager")
|
val lastVisibleElementFun: () -> Int = layoutManager ?.findLastVisibleItemPositionGetter() ?: error("Currently supported only linear and grid layout manager")
|
||||||
val lastVisibleFlow = MutableStateFlow(lastVisibleElementFun())
|
val lastVisibleFlow = MutableStateFlow(lastVisibleElementFun())
|
||||||
addOnScrollListener(
|
addOnScrollListener(
|
||||||
object : RecyclerView.OnScrollListener() {
|
object : RecyclerView.OnScrollListener() {
|
||||||
|
@@ -8,10 +8,9 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.0.0'
|
classpath 'com.android.tools.build:gradle:4.0.2'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||||
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
|
|
||||||
classpath "com.getkeepsafe.dexcount:dexcount-gradle-plugin:$dexcount_version"
|
classpath "com.getkeepsafe.dexcount:dexcount-gradle-plugin:$dexcount_version"
|
||||||
classpath "com.github.breadmoirai:github-release:$github_release_plugin_version"
|
classpath "com.github.breadmoirai:github-release:$github_release_plugin_version"
|
||||||
classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
|
classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
|
||||||
|
@@ -12,4 +12,7 @@ function assert_success() {
|
|||||||
export RELEASE_MODE=true
|
export RELEASE_MODE=true
|
||||||
project="$1"
|
project="$1"
|
||||||
|
|
||||||
assert_success ./gradlew clean "$project:clean" "$project:build" "$project:publishToMavenLocal" "$project:bintrayUpload"
|
assert_success ./gradlew clean
|
||||||
|
assert_success ./gradlew "$project:build"
|
||||||
|
assert_success ./gradlew "$project:publishToMavenLocal"
|
||||||
|
assert_success ./gradlew "$project:bintrayUpload"
|
||||||
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
@RequiresOptIn(
|
||||||
|
"It is possible, that behaviour of this thing will be changed or removed in future releases",
|
||||||
|
RequiresOptIn.Level.WARNING
|
||||||
|
)
|
||||||
|
@Target(
|
||||||
|
AnnotationTarget.CLASS,
|
||||||
|
AnnotationTarget.CONSTRUCTOR,
|
||||||
|
AnnotationTarget.FIELD,
|
||||||
|
AnnotationTarget.PROPERTY,
|
||||||
|
AnnotationTarget.PROPERTY_GETTER,
|
||||||
|
AnnotationTarget.PROPERTY_SETTER,
|
||||||
|
AnnotationTarget.FUNCTION,
|
||||||
|
AnnotationTarget.TYPE,
|
||||||
|
AnnotationTarget.TYPEALIAS,
|
||||||
|
AnnotationTarget.TYPE_PARAMETER
|
||||||
|
)
|
||||||
|
annotation class PreviewFeature
|
||||||
|
|
||||||
|
@RequiresOptIn(
|
||||||
|
"This thing is marked as warned. See message of warn to get more info",
|
||||||
|
RequiresOptIn.Level.WARNING
|
||||||
|
)
|
||||||
|
@Target(
|
||||||
|
AnnotationTarget.CLASS,
|
||||||
|
AnnotationTarget.CONSTRUCTOR,
|
||||||
|
AnnotationTarget.FIELD,
|
||||||
|
AnnotationTarget.PROPERTY,
|
||||||
|
AnnotationTarget.PROPERTY_GETTER,
|
||||||
|
AnnotationTarget.PROPERTY_SETTER,
|
||||||
|
AnnotationTarget.FUNCTION,
|
||||||
|
AnnotationTarget.TYPE,
|
||||||
|
AnnotationTarget.TYPEALIAS,
|
||||||
|
AnnotationTarget.TYPE_PARAMETER
|
||||||
|
)
|
||||||
|
annotation class Warning(val message: String)
|
@@ -0,0 +1,13 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE")
|
||||||
|
|
||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
|
||||||
|
inline fun Resources.getSp(
|
||||||
|
resId: Int
|
||||||
|
) = getDimension(resId) / displayMetrics.scaledDensity
|
||||||
|
|
||||||
|
inline fun Resources.getDp(
|
||||||
|
resId: Int
|
||||||
|
) = getDimension(resId) * displayMetrics.density
|
@@ -0,0 +1,76 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.Animation
|
||||||
|
import android.view.animation.Transformation
|
||||||
|
|
||||||
|
@PreviewFeature
|
||||||
|
fun View.expand(
|
||||||
|
duration: Long = 500,
|
||||||
|
targetWidth: Int = ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
targetHeight: Int = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
) {
|
||||||
|
measure(targetWidth, targetHeight)
|
||||||
|
val measuredHeight: Int = measuredHeight
|
||||||
|
layoutParams.height = 0
|
||||||
|
visibility = View.VISIBLE
|
||||||
|
val a: Animation = object : Animation() {
|
||||||
|
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
|
||||||
|
super.applyTransformation(interpolatedTime, t)
|
||||||
|
layoutParams.height = if (interpolatedTime == 1f) targetHeight else (measuredHeight * interpolatedTime).toInt()
|
||||||
|
requestLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun willChangeBounds(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.duration = duration
|
||||||
|
|
||||||
|
startAnimation(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreviewFeature
|
||||||
|
fun View.collapse(duration: Long = 500) {
|
||||||
|
val initialHeight: Int = measuredHeight
|
||||||
|
val a: Animation = object : Animation() {
|
||||||
|
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
|
||||||
|
if (interpolatedTime == 1f) {
|
||||||
|
visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt()
|
||||||
|
requestLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun willChangeBounds(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.duration = duration
|
||||||
|
|
||||||
|
startAnimation(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreviewFeature
|
||||||
|
inline val View.isCollapsed
|
||||||
|
get() = visibility == View.GONE
|
||||||
|
|
||||||
|
@PreviewFeature
|
||||||
|
inline val View.isExpanded
|
||||||
|
get() = !isCollapsed
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true in case of expanding
|
||||||
|
*/
|
||||||
|
@PreviewFeature
|
||||||
|
fun View.toggleExpandState(duration: Long = 500): Boolean = if (isCollapsed) {
|
||||||
|
expand(duration)
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
collapse(duration)
|
||||||
|
false
|
||||||
|
}
|
@@ -0,0 +1,34 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE", "unused")
|
||||||
|
|
||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
|
||||||
|
inline val View.enabled
|
||||||
|
get() = isEnabled
|
||||||
|
|
||||||
|
inline val View.disabled
|
||||||
|
get() = !enabled
|
||||||
|
|
||||||
|
fun View.disable() {
|
||||||
|
if (this is ViewGroup) {
|
||||||
|
(0 until childCount).forEach { getChildAt(it).disable() }
|
||||||
|
}
|
||||||
|
isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.enable() {
|
||||||
|
if (this is ViewGroup) {
|
||||||
|
(0 until childCount).forEach { getChildAt(it).enable() }
|
||||||
|
}
|
||||||
|
isEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.toggleEnabledState(enabled: Boolean) {
|
||||||
|
if (enabled) {
|
||||||
|
enable()
|
||||||
|
} else {
|
||||||
|
disable()
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,35 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE", "unused")
|
||||||
|
|
||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
inline val View.gone
|
||||||
|
get() = visibility == View.GONE
|
||||||
|
inline fun View.gone() {
|
||||||
|
visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
inline val View.hidden
|
||||||
|
get() = visibility == View.INVISIBLE
|
||||||
|
inline fun View.hide() {
|
||||||
|
visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
inline val View.shown
|
||||||
|
get() = visibility == View.VISIBLE
|
||||||
|
inline fun View.show() {
|
||||||
|
visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.toggleVisibility(goneOnHide: Boolean = true) {
|
||||||
|
if (isShown) {
|
||||||
|
if (goneOnHide) {
|
||||||
|
gone()
|
||||||
|
} else {
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
@@ -0,0 +1,5 @@
|
|||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.FlowCollector
|
||||||
|
|
||||||
|
suspend inline operator fun <T> FlowCollector<T>.invoke(value: T) = emit(value)
|
@@ -0,0 +1,8 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE")
|
||||||
|
|
||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
|
||||||
|
inline operator fun <T> Flow<T>.plus(other: Flow<T>) = merge(this, other)
|
@@ -12,6 +12,9 @@ android {
|
|||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
}
|
}
|
||||||
|
debug {
|
||||||
|
debuggable true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
@@ -28,4 +31,8 @@ android {
|
|||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
id "org.jetbrains.dokka"
|
id "org.jetbrains.dokka"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,11 +10,12 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internalProject = { name ->
|
internalProject = { name ->
|
||||||
if (releaseMode) {
|
// if (releaseMode) {
|
||||||
"$group:$name:$version"
|
// "$group:$name:$version"
|
||||||
} else {
|
// } else {
|
||||||
projectByName("$name")
|
// projectByName("$name")
|
||||||
}
|
// }
|
||||||
|
projectByName("$name")
|
||||||
}
|
}
|
||||||
|
|
||||||
releaseMode = (project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") || System.getenv('RELEASE_MODE') == "true"
|
releaseMode = (project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") || System.getenv('RELEASE_MODE') == "true"
|
||||||
|
@@ -5,28 +5,27 @@ kotlin.incremental=true
|
|||||||
kotlin.incremental.js=true
|
kotlin.incremental.js=true
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
org.gradle.jvmargs=-Xmx4096m
|
|
||||||
|
|
||||||
kotlin_version=1.4.10
|
kotlin_version=1.4.20
|
||||||
kotlin_coroutines_version=1.4.1
|
kotlin_coroutines_version=1.4.2
|
||||||
kotlin_serialisation_core_version=1.0.1
|
kotlin_serialisation_core_version=1.0.1
|
||||||
kotlin_exposed_version=0.28.1
|
kotlin_exposed_version=0.28.1
|
||||||
|
|
||||||
ktor_version=1.4.1
|
ktor_version=1.4.2
|
||||||
|
|
||||||
klockVersion=1.12.1
|
klockVersion=2.0.0
|
||||||
|
|
||||||
gradle_bintray_plugin_version=1.8.5
|
|
||||||
github_release_plugin_version=2.2.12
|
github_release_plugin_version=2.2.12
|
||||||
|
|
||||||
uuidVersion=0.2.2
|
uuidVersion=0.2.3
|
||||||
|
|
||||||
# ANDROID
|
# ANDROID
|
||||||
|
|
||||||
core_ktx_version=1.3.2
|
core_ktx_version=1.3.2
|
||||||
androidx_recycler_version=1.1.0
|
androidx_recycler_version=1.1.0
|
||||||
|
appcompat_version=1.2.0
|
||||||
|
|
||||||
android_minSdkVersion=24
|
android_minSdkVersion=19
|
||||||
android_compileSdkVersion=30
|
android_compileSdkVersion=30
|
||||||
android_buildToolsVersion=30.0.2
|
android_buildToolsVersion=30.0.2
|
||||||
dexcount_version=2.0.0-RC1
|
dexcount_version=2.0.0-RC1
|
||||||
@@ -36,10 +35,10 @@ espresso_core=3.3.0
|
|||||||
|
|
||||||
# Dokka
|
# Dokka
|
||||||
|
|
||||||
dokka_version=1.4.0
|
dokka_version=1.4.10.2
|
||||||
|
|
||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.3.1
|
version=0.4.8
|
||||||
android_code_version=1
|
android_code_version=12
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
@@ -64,10 +64,11 @@ inline fun <T> HttpClient.createStandardWebsocketFlow(
|
|||||||
inline fun <T> HttpClient.createStandardWebsocketFlow(
|
inline fun <T> HttpClient.createStandardWebsocketFlow(
|
||||||
url: String,
|
url: String,
|
||||||
crossinline checkReconnection: (Throwable?) -> Boolean = { true },
|
crossinline checkReconnection: (Throwable?) -> Boolean = { true },
|
||||||
deserializer: DeserializationStrategy<T>
|
deserializer: DeserializationStrategy<T>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
) = createStandardWebsocketFlow(
|
) = createStandardWebsocketFlow(
|
||||||
url,
|
url,
|
||||||
checkReconnection
|
checkReconnection
|
||||||
) {
|
) {
|
||||||
standardKtorSerialFormat.decodeDefault(deserializer, it)
|
serialFormat.decodeDefault(deserializer, it)
|
||||||
}
|
}
|
||||||
|
@@ -4,32 +4,61 @@ import dev.inmo.micro_utils.ktor.common.*
|
|||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.request.get
|
import io.ktor.client.request.get
|
||||||
import io.ktor.client.request.post
|
import io.ktor.client.request.post
|
||||||
import kotlinx.serialization.DeserializationStrategy
|
import kotlinx.serialization.*
|
||||||
import kotlinx.serialization.SerializationStrategy
|
|
||||||
|
|
||||||
typealias BodyPair<T> = Pair<SerializationStrategy<T>, T>
|
typealias BodyPair<T> = Pair<SerializationStrategy<T>, T>
|
||||||
|
|
||||||
|
class UnifiedRequester(
|
||||||
|
private val client: HttpClient = HttpClient(),
|
||||||
|
private val serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
|
) {
|
||||||
|
suspend fun <ResultType> uniget(
|
||||||
|
url: String,
|
||||||
|
resultDeserializer: DeserializationStrategy<ResultType>
|
||||||
|
): ResultType = client.get<StandardKtorSerialInputData>(
|
||||||
|
url
|
||||||
|
).let {
|
||||||
|
serialFormat.decodeDefault(resultDeserializer, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun <T> encodeUrlQueryValue(
|
||||||
|
serializationStrategy: SerializationStrategy<T>,
|
||||||
|
value: T
|
||||||
|
) = serialFormat.encodeHex(
|
||||||
|
serializationStrategy,
|
||||||
|
value
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun <BodyType, ResultType> unipost(
|
||||||
|
url: String,
|
||||||
|
bodyInfo: BodyPair<BodyType>,
|
||||||
|
resultDeserializer: DeserializationStrategy<ResultType>
|
||||||
|
) = client.post<StandardKtorSerialInputData>(url) {
|
||||||
|
body = serialFormat.encodeDefault(bodyInfo.first, bodyInfo.second)
|
||||||
|
}.let {
|
||||||
|
serialFormat.decodeDefault(resultDeserializer, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> createStandardWebsocketFlow(
|
||||||
|
url: String,
|
||||||
|
checkReconnection: (Throwable?) -> Boolean = { true },
|
||||||
|
deserializer: DeserializationStrategy<T>
|
||||||
|
) = client.createStandardWebsocketFlow(url, checkReconnection, deserializer, serialFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
val defaultRequester = UnifiedRequester()
|
||||||
|
|
||||||
suspend fun <ResultType> HttpClient.uniget(
|
suspend fun <ResultType> HttpClient.uniget(
|
||||||
url: String,
|
url: String,
|
||||||
resultDeserializer: DeserializationStrategy<ResultType>
|
resultDeserializer: DeserializationStrategy<ResultType>
|
||||||
) = get<StandardKtorSerialInputData>(
|
) = defaultRequester.uniget(url, resultDeserializer)
|
||||||
url
|
|
||||||
).let {
|
|
||||||
standardKtorSerialFormat.decodeDefault(resultDeserializer, it)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun <T> SerializationStrategy<T>.encodeUrlQueryValue(value: T) = standardKtorSerialFormat.encodeHex(
|
fun <T> SerializationStrategy<T>.encodeUrlQueryValue(value: T) = defaultRequester.encodeUrlQueryValue(this, value)
|
||||||
this,
|
|
||||||
value
|
|
||||||
)
|
|
||||||
|
|
||||||
suspend fun <BodyType, ResultType> HttpClient.unipost(
|
suspend fun <BodyType, ResultType> HttpClient.unipost(
|
||||||
url: String,
|
url: String,
|
||||||
bodyInfo: BodyPair<BodyType>,
|
bodyInfo: BodyPair<BodyType>,
|
||||||
resultDeserializer: DeserializationStrategy<ResultType>
|
resultDeserializer: DeserializationStrategy<ResultType>
|
||||||
) = post<StandardKtorSerialInputData>(url) {
|
) = defaultRequester.unipost(url, bodyInfo, resultDeserializer)
|
||||||
body = standardKtorSerialFormat.encodeDefault(bodyInfo.first, bodyInfo.second)
|
|
||||||
}.let {
|
|
||||||
standardKtorSerialFormat.decodeDefault(resultDeserializer, it)
|
|
||||||
}
|
|
||||||
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
@@ -3,16 +3,28 @@ package dev.inmo.micro_utils.ktor.common
|
|||||||
typealias QueryParam = Pair<String, String?>
|
typealias QueryParam = Pair<String, String?>
|
||||||
typealias QueryParams = Map<String, String?>
|
typealias QueryParams = Map<String, String?>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create query part which includes key=value pairs separated with &
|
||||||
|
*/
|
||||||
val QueryParams.asUrlQuery: String
|
val QueryParams.asUrlQuery: String
|
||||||
get() = keys.joinToString("&") { "${it}${get(it) ?.let { value -> "=$value" }}" }
|
get() = keys.joinToString("&") { "${it}${get(it) ?.let { value -> "=$value" }}" }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create query part which includes key=value pairs separated with &
|
||||||
|
*/
|
||||||
val List<QueryParam>.asUrlQuery: String
|
val List<QueryParam>.asUrlQuery: String
|
||||||
get() = joinToString("&") { (key, value) -> "${key}${value ?.let { _ -> "=$value" }}" }
|
get() = joinToString("&") { (key, value) -> "${key}${value ?.let { _ -> "=$value" }}" }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create query part which includes key=value pairs separated with & and attach to receiver
|
||||||
|
*/
|
||||||
fun String.includeQueryParams(
|
fun String.includeQueryParams(
|
||||||
queryParams: QueryParams
|
queryParams: QueryParams
|
||||||
): String = "$this${if(queryParams.isNotEmpty()) "${if (contains("?")) "&" else "?"}${queryParams.asUrlQuery}" else ""}"
|
): String = "$this${if(queryParams.isNotEmpty()) "${if (contains("?")) "&" else "?"}${queryParams.asUrlQuery}" else ""}"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create query part which includes key=value pairs separated with & and attach to receiver
|
||||||
|
*/
|
||||||
fun String.includeQueryParams(
|
fun String.includeQueryParams(
|
||||||
queryParams: List<QueryParam>
|
queryParams: List<QueryParam>
|
||||||
): String = "$this${if (contains("?")) "&" else "?"}${queryParams.asUrlQuery}"
|
): String = "$this${if (contains("?")) "&" else "?"}${queryParams.asUrlQuery}"
|
||||||
|
@@ -33,10 +33,11 @@ fun <T> Route.includeWebsocketHandling(
|
|||||||
fun <T> Route.includeWebsocketHandling(
|
fun <T> Route.includeWebsocketHandling(
|
||||||
suburl: String,
|
suburl: String,
|
||||||
flow: Flow<T>,
|
flow: Flow<T>,
|
||||||
serializer: SerializationStrategy<T>
|
serializer: SerializationStrategy<T>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
) = includeWebsocketHandling(
|
) = includeWebsocketHandling(
|
||||||
suburl,
|
suburl,
|
||||||
flow
|
flow
|
||||||
) {
|
) {
|
||||||
standardKtorSerialFormat.encodeDefault(serializer, it)
|
serialFormat.encodeDefault(serializer, it)
|
||||||
}
|
}
|
||||||
|
@@ -3,12 +3,87 @@ package dev.inmo.micro_utils.ktor.server
|
|||||||
import dev.inmo.micro_utils.coroutines.safely
|
import dev.inmo.micro_utils.coroutines.safely
|
||||||
import dev.inmo.micro_utils.ktor.common.*
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
import io.ktor.application.ApplicationCall
|
import io.ktor.application.ApplicationCall
|
||||||
|
import io.ktor.application.call
|
||||||
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.request.receive
|
import io.ktor.request.receive
|
||||||
import io.ktor.response.respond
|
import io.ktor.response.respond
|
||||||
import io.ktor.response.respondBytes
|
import io.ktor.response.respondBytes
|
||||||
import kotlinx.serialization.DeserializationStrategy
|
import io.ktor.routing.Route
|
||||||
import kotlinx.serialization.SerializationStrategy
|
import io.ktor.util.pipeline.PipelineContext
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
|
class UnifiedRouter(
|
||||||
|
private val serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
|
||||||
|
private val serialFormatContentType: ContentType = standardKtorSerialFormatContentType
|
||||||
|
) {
|
||||||
|
fun <T> Route.includeWebsocketHandling(
|
||||||
|
suburl: String,
|
||||||
|
flow: Flow<T>,
|
||||||
|
serializer: SerializationStrategy<T>
|
||||||
|
) = includeWebsocketHandling(suburl, flow, serializer, serialFormat)
|
||||||
|
|
||||||
|
suspend fun <T> PipelineContext<*, ApplicationCall>.unianswer(
|
||||||
|
answerSerializer: SerializationStrategy<T>,
|
||||||
|
answer: T
|
||||||
|
) {
|
||||||
|
call.respondBytes (
|
||||||
|
serialFormat.encodeDefault(answerSerializer, answer),
|
||||||
|
serialFormatContentType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun <T> PipelineContext<*, ApplicationCall>.uniload(
|
||||||
|
deserializer: DeserializationStrategy<T>
|
||||||
|
) = safely {
|
||||||
|
serialFormat.decodeDefault(
|
||||||
|
deserializer,
|
||||||
|
call.receive()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun PipelineContext<*, ApplicationCall>.getParameterOrSendError(
|
||||||
|
field: String
|
||||||
|
) = call.parameters[field].also {
|
||||||
|
if (it == null) {
|
||||||
|
call.respond(HttpStatusCode.BadRequest, "Request must contains $field")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PipelineContext<*, ApplicationCall>.getQueryParameter(
|
||||||
|
field: String
|
||||||
|
) = call.request.queryParameters[field]
|
||||||
|
|
||||||
|
suspend fun PipelineContext<*, ApplicationCall>.getQueryParameterOrSendError(
|
||||||
|
field: String
|
||||||
|
) = getQueryParameter(field).also {
|
||||||
|
if (it == null) {
|
||||||
|
call.respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> PipelineContext<*, ApplicationCall>.decodeUrlQueryValue(
|
||||||
|
field: String,
|
||||||
|
deserializer: DeserializationStrategy<T>
|
||||||
|
) = getQueryParameter(field) ?.let {
|
||||||
|
serialFormat.decodeHex(
|
||||||
|
deserializer,
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun <T> PipelineContext<*, ApplicationCall>.decodeUrlQueryValueOrSendError(
|
||||||
|
field: String,
|
||||||
|
deserializer: DeserializationStrategy<T>
|
||||||
|
) = decodeUrlQueryValue(field, deserializer).also {
|
||||||
|
if (it == null) {
|
||||||
|
call.respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val defaultUnifiedRouter = UnifiedRouter()
|
||||||
|
|
||||||
suspend fun <T> ApplicationCall.unianswer(
|
suspend fun <T> ApplicationCall.unianswer(
|
||||||
answerSerializer: SerializationStrategy<T>,
|
answerSerializer: SerializationStrategy<T>,
|
||||||
|
@@ -1,60 +0,0 @@
|
|||||||
apply plugin: 'maven-publish'
|
|
||||||
|
|
||||||
task javadocsJar(type: Jar) {
|
|
||||||
classifier = 'javadoc'
|
|
||||||
}
|
|
||||||
|
|
||||||
afterEvaluate {
|
|
||||||
project.publishing.publications.all {
|
|
||||||
// rename artifacts
|
|
||||||
groupId "${project.group}"
|
|
||||||
if (it.name.contains('kotlinMultiplatform')) {
|
|
||||||
artifactId = "${project.name}"
|
|
||||||
} else {
|
|
||||||
artifactId = "${project.name}-$name"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
publishing {
|
|
||||||
publications.all {
|
|
||||||
artifact javadocsJar
|
|
||||||
|
|
||||||
pom {
|
|
||||||
description = ""
|
|
||||||
name = "${project.name}"
|
|
||||||
url = "https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror"
|
|
||||||
|
|
||||||
scm {
|
|
||||||
developerConnection = "scm:git:[fetch=]ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git[push=]ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git"
|
|
||||||
url = "ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git"
|
|
||||||
}
|
|
||||||
|
|
||||||
developers {
|
|
||||||
|
|
||||||
developer {
|
|
||||||
id = "InsanusMokrassar"
|
|
||||||
name = "Aleksei Ovsiannikov"
|
|
||||||
email = "ovsyannikov.alexey95@gmail.com"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
developer {
|
|
||||||
id = "000Sanya"
|
|
||||||
name = "Syrov Aleksandr"
|
|
||||||
email = "000sanya.000sanya@gmail.com"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
licenses {
|
|
||||||
|
|
||||||
license {
|
|
||||||
name = "Apache Software License 2.0"
|
|
||||||
url = "https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror/src/master/LICENSE"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
@@ -4,7 +4,9 @@ project.group = "$group"
|
|||||||
apply from: "$publishGradlePath"
|
apply from: "$publishGradlePath"
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
android {}
|
android {
|
||||||
|
publishAllLibraryVariants()
|
||||||
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
|
@@ -10,7 +10,7 @@ kotlin {
|
|||||||
nodejs()
|
nodejs()
|
||||||
}
|
}
|
||||||
android {
|
android {
|
||||||
publishLibraryVariants("release")
|
publishAllLibraryVariants()
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
@@ -22,6 +22,12 @@ interface Pagination {
|
|||||||
val size: Int
|
val size: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logical shortcut for comparison that page is 0
|
||||||
|
*/
|
||||||
|
inline val Pagination.isFirstPage
|
||||||
|
get() = page == 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First number in index of objects. It can be used as offset for databases or other data sources
|
* First number in index of objects. It can be used as offset for databases or other data sources
|
||||||
*/
|
*/
|
||||||
|
@@ -0,0 +1,41 @@
|
|||||||
|
package dev.inmo.micro_utils.pagination.utils
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.pagination.*
|
||||||
|
|
||||||
|
class PaginatedIterator<T>(
|
||||||
|
pageSize: Int,
|
||||||
|
private val countGetter: () -> Long,
|
||||||
|
private val paginationResultGetter: Pagination.() -> PaginationResult<T>
|
||||||
|
) : Iterator<T> {
|
||||||
|
private var pagination = FirstPagePagination(pageSize)
|
||||||
|
private val currentStack = mutableListOf<T>()
|
||||||
|
override fun hasNext(): Boolean = currentStack.isNotEmpty() || (countGetter() < pagination.lastIndexExclusive)
|
||||||
|
|
||||||
|
override fun next(): T {
|
||||||
|
if (currentStack.isEmpty()) {
|
||||||
|
val resultPagination = paginationResultGetter.invoke(pagination)
|
||||||
|
currentStack.addAll(resultPagination.results)
|
||||||
|
require(currentStack.isNotEmpty()) { "There is no elements left" }
|
||||||
|
pagination = resultPagination.nextPage()
|
||||||
|
}
|
||||||
|
return currentStack.removeFirst()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PaginatedIterable<T>(
|
||||||
|
private val pageSize: Int,
|
||||||
|
private val countGetter: () -> Long,
|
||||||
|
private val paginationResultGetter: Pagination.() -> PaginationResult<T>
|
||||||
|
) : Iterable<T> {
|
||||||
|
override fun iterator(): Iterator<T> = PaginatedIterator(pageSize, countGetter, paginationResultGetter)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will make iterable using incoming [countGetter] and [paginationResultGetter]
|
||||||
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <T> makeIterable(
|
||||||
|
noinline countGetter: () -> Long,
|
||||||
|
pageSize: Int = defaultMediumPageSize,
|
||||||
|
noinline paginationResultGetter: Pagination.() -> PaginationResult<T>
|
||||||
|
): Iterable<T> = PaginatedIterable(pageSize, countGetter, paginationResultGetter)
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
@@ -1 +1 @@
|
|||||||
{"bintrayConfig":{"repo":"MicroUtils","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/MicroUtils","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror/src/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"","url":"https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror","vcsUrl":"ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}]},"type":"Multiplatform"}
|
{"bintrayConfig":{"repo":"MicroUtils","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/MicroUtils","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror/src/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"","url":"https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror","vcsUrl":"ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}]}}
|
119
publish.gradle
119
publish.gradle
@@ -1,59 +1,76 @@
|
|||||||
apply plugin: 'com.jfrog.bintray'
|
apply plugin: 'maven-publish'
|
||||||
|
|
||||||
apply from: "$publishMavenPath"
|
task javadocsJar(type: Jar) {
|
||||||
|
classifier = 'javadoc'
|
||||||
bintray {
|
}
|
||||||
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
|
task sourceJar (type : Jar) {
|
||||||
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
|
classifier = 'sources'
|
||||||
filesSpec {
|
|
||||||
from "${buildDir}/publications/"
|
|
||||||
eachFile {
|
|
||||||
String directorySubname = it.getFile().parentFile.name
|
|
||||||
if (it.getName() == "module.json") {
|
|
||||||
if (directorySubname == "kotlinMultiplatform") {
|
|
||||||
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
|
|
||||||
} else {
|
|
||||||
it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (directorySubname == "kotlinMultiplatform" && it.getName() == "pom-default.xml") {
|
|
||||||
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.pom")
|
|
||||||
} else {
|
|
||||||
it.exclude()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
into "${project.group}".replace(".", "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
publish = true
|
|
||||||
override = true
|
|
||||||
|
|
||||||
pkg {
|
|
||||||
repo = "MicroUtils"
|
|
||||||
name = "${project.name}"
|
|
||||||
vcsUrl = "https://github.com/InsanusMokrassar/MicroUtils"
|
|
||||||
licenses = ["Apache-2.0"]
|
|
||||||
version {
|
|
||||||
name = "${project.version}"
|
|
||||||
released = new Date()
|
|
||||||
vcsTag = "${project.version}"
|
|
||||||
gpg {
|
|
||||||
sign = true
|
|
||||||
passphrase = project.hasProperty('signing.gnupg.passphrase') ? project.property('signing.gnupg.passphrase') : System.getenv('signing.gnupg.passphrase')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bintrayUpload.doFirst {
|
afterEvaluate {
|
||||||
publications = publishing.publications.collect {
|
project.publishing.publications.all {
|
||||||
|
// rename artifacts
|
||||||
|
groupId "${project.group}"
|
||||||
if (it.name.contains('kotlinMultiplatform')) {
|
if (it.name.contains('kotlinMultiplatform')) {
|
||||||
null
|
artifactId = "${project.name}"
|
||||||
|
artifact sourceJar
|
||||||
} else {
|
} else {
|
||||||
it.name
|
artifactId = "${project.name}-$name"
|
||||||
}
|
}
|
||||||
} - null
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bintrayUpload.dependsOn publishToMavenLocal
|
publishing {
|
||||||
|
publications.all {
|
||||||
|
artifact javadocsJar
|
||||||
|
|
||||||
|
pom {
|
||||||
|
description = ""
|
||||||
|
name = "${project.name}"
|
||||||
|
url = "https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror"
|
||||||
|
|
||||||
|
scm {
|
||||||
|
developerConnection = "scm:git:[fetch=]ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git[push=]ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git"
|
||||||
|
url = "ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git"
|
||||||
|
}
|
||||||
|
|
||||||
|
developers {
|
||||||
|
|
||||||
|
developer {
|
||||||
|
id = "InsanusMokrassar"
|
||||||
|
name = "Aleksei Ovsiannikov"
|
||||||
|
email = "ovsyannikov.alexey95@gmail.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
developer {
|
||||||
|
id = "000Sanya"
|
||||||
|
name = "Syrov Aleksandr"
|
||||||
|
email = "000sanya.000sanya@gmail.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
licenses {
|
||||||
|
|
||||||
|
license {
|
||||||
|
name = "Apache Software License 2.0"
|
||||||
|
url = "https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror/src/master/LICENSE"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = "bintray"
|
||||||
|
url = uri("https://api.bintray.com/maven/${project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')}/MicroUtils/${project.name}/;publish=1;override=1")
|
||||||
|
credentials {
|
||||||
|
username = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
|
||||||
|
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
@@ -18,6 +17,11 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jvmMain {
|
||||||
|
dependencies {
|
||||||
|
api internalProject("micro_utils.common")
|
||||||
|
}
|
||||||
|
}
|
||||||
androidMain {
|
androidMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api "androidx.core:core-ktx:$core_ktx_version"
|
api "androidx.core:core-ktx:$core_ktx_version"
|
||||||
|
@@ -6,4 +6,16 @@ interface MapperRepo<FromKey, FromValue, ToKey, ToValue> {
|
|||||||
|
|
||||||
suspend fun ToKey.toInnerKey() = this as FromKey
|
suspend fun ToKey.toInnerKey() = this as FromKey
|
||||||
suspend fun ToValue.toInnerValue() = this as FromValue
|
suspend fun ToValue.toInnerValue() = this as FromValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> mapper(
|
||||||
|
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 },
|
||||||
|
) = object : MapperRepo<FromKey, FromValue, ToKey, ToValue> {
|
||||||
|
override suspend fun FromKey.toOutKey(): ToKey = keyFromToTo()
|
||||||
|
override suspend fun FromValue.toOutValue(): ToValue = valueFromToTo()
|
||||||
|
override suspend fun ToKey.toInnerKey(): FromKey = keyToToFrom()
|
||||||
|
override suspend fun ToValue.toInnerValue(): FromValue = valueToToFrom()
|
||||||
|
}
|
||||||
|
@@ -6,6 +6,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
interface ReadOneToManyKeyValueRepo<Key, Value> : Repo {
|
interface ReadOneToManyKeyValueRepo<Key, Value> : Repo {
|
||||||
suspend fun get(k: Key, pagination: Pagination, reversed: Boolean = false): PaginationResult<Value>
|
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(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
|
||||||
|
suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
|
||||||
suspend fun contains(k: Key): Boolean
|
suspend fun contains(k: Key): Boolean
|
||||||
suspend fun contains(k: Key, v: Value): Boolean
|
suspend fun contains(k: Key, v: Value): Boolean
|
||||||
suspend fun count(k: Key): Long
|
suspend fun count(k: Key): Long
|
||||||
@@ -35,6 +36,7 @@ interface ReadOneToManyKeyValueRepo<Key, Value> : Repo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
typealias ReadKeyValuesRepo<Key,Value> = ReadOneToManyKeyValueRepo<Key, Value>
|
||||||
|
|
||||||
interface WriteOneToManyKeyValueRepo<Key, Value> : Repo {
|
interface WriteOneToManyKeyValueRepo<Key, Value> : Repo {
|
||||||
val onNewValue: Flow<Pair<Key, Value>>
|
val onNewValue: Flow<Pair<Key, Value>>
|
||||||
@@ -46,7 +48,13 @@ interface WriteOneToManyKeyValueRepo<Key, Value> : Repo {
|
|||||||
suspend fun remove(toRemove: Map<Key, List<Value>>)
|
suspend fun remove(toRemove: Map<Key, List<Value>>)
|
||||||
|
|
||||||
suspend fun clear(k: Key)
|
suspend fun clear(k: Key)
|
||||||
|
|
||||||
|
suspend fun set(toSet: Map<Key, List<Value>>) {
|
||||||
|
toSet.keys.forEach { key -> clear(key) }
|
||||||
|
add(toSet)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
typealias WriteKeyValuesRepo<Key,Value> = WriteOneToManyKeyValueRepo<Key, Value>
|
||||||
|
|
||||||
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.add(
|
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.add(
|
||||||
keysAndValues: List<Pair<Key, List<Value>>>
|
keysAndValues: List<Pair<Key, List<Value>>>
|
||||||
@@ -64,7 +72,24 @@ suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.add(
|
|||||||
k: Key, vararg v: Value
|
k: Key, vararg v: Value
|
||||||
) = add(k, v.toList())
|
) = add(k, v.toList())
|
||||||
|
|
||||||
|
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.set(
|
||||||
|
keysAndValues: List<Pair<Key, List<Value>>>
|
||||||
|
) = set(keysAndValues.toMap())
|
||||||
|
|
||||||
|
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.set(
|
||||||
|
vararg keysAndValues: Pair<Key, List<Value>>
|
||||||
|
) = set(keysAndValues.toMap())
|
||||||
|
|
||||||
|
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.set(
|
||||||
|
k: Key, v: List<Value>
|
||||||
|
) = set(mapOf(k to v))
|
||||||
|
|
||||||
|
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.set(
|
||||||
|
k: Key, vararg v: Value
|
||||||
|
) = set(k, v.toList())
|
||||||
|
|
||||||
interface OneToManyKeyValueRepo<Key, Value> : ReadOneToManyKeyValueRepo<Key, Value>, WriteOneToManyKeyValueRepo<Key, Value>
|
interface OneToManyKeyValueRepo<Key, Value> : ReadOneToManyKeyValueRepo<Key, Value>, WriteOneToManyKeyValueRepo<Key, Value>
|
||||||
|
typealias KeyValuesRepo<Key,Value> = OneToManyKeyValueRepo<Key, Value>
|
||||||
|
|
||||||
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
|
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
|
||||||
keysAndValues: List<Pair<Key, List<Value>>>
|
keysAndValues: List<Pair<Key, List<Value>>>
|
||||||
|
@@ -10,6 +10,7 @@ interface ReadStandardCRUDRepo<ObjectType, IdType> : Repo {
|
|||||||
suspend fun contains(id: IdType): Boolean
|
suspend fun contains(id: IdType): Boolean
|
||||||
suspend fun count(): Long
|
suspend fun count(): Long
|
||||||
}
|
}
|
||||||
|
typealias ReadCRUDRepo<ObjectType, IdType> = ReadStandardCRUDRepo<ObjectType, IdType>
|
||||||
|
|
||||||
typealias UpdatedValuePair<IdType, ValueType> = Pair<IdType, ValueType>
|
typealias UpdatedValuePair<IdType, ValueType> = Pair<IdType, ValueType>
|
||||||
val <IdType> UpdatedValuePair<IdType, *>.id
|
val <IdType> UpdatedValuePair<IdType, *>.id
|
||||||
@@ -27,6 +28,7 @@ interface WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> : Repo {
|
|||||||
suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType>
|
suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType>
|
||||||
suspend fun deleteById(ids: List<IdType>)
|
suspend fun deleteById(ids: List<IdType>)
|
||||||
}
|
}
|
||||||
|
typealias WriteCRUDRepo<ObjectType, IdType, InputValueType> = WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>
|
||||||
|
|
||||||
suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>.create(
|
suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>.create(
|
||||||
vararg values: InputValueType
|
vararg values: InputValueType
|
||||||
@@ -39,4 +41,5 @@ suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectTyp
|
|||||||
) = deleteById(ids.toList())
|
) = deleteById(ids.toList())
|
||||||
|
|
||||||
interface StandardCRUDRepo<ObjectType, IdType, InputValueType> : ReadStandardCRUDRepo<ObjectType, IdType>,
|
interface StandardCRUDRepo<ObjectType, IdType, InputValueType> : ReadStandardCRUDRepo<ObjectType, IdType>,
|
||||||
WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>
|
WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>
|
||||||
|
typealias CRUDRepo<ObjectType, IdType, InputValueType> = StandardCRUDRepo<ObjectType, IdType, InputValueType>
|
@@ -8,9 +8,11 @@ interface ReadStandardKeyValueRepo<Key, Value> : Repo {
|
|||||||
suspend fun get(k: Key): Value?
|
suspend fun get(k: Key): Value?
|
||||||
suspend fun values(pagination: Pagination, reversed: Boolean = false): PaginationResult<Value>
|
suspend fun values(pagination: Pagination, reversed: Boolean = false): PaginationResult<Value>
|
||||||
suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
|
suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
|
||||||
|
suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
|
||||||
suspend fun contains(key: Key): Boolean
|
suspend fun contains(key: Key): Boolean
|
||||||
suspend fun count(): Long
|
suspend fun count(): Long
|
||||||
}
|
}
|
||||||
|
typealias ReadKeyValueRepo<Key,Value> = ReadStandardKeyValueRepo<Key, Value>
|
||||||
|
|
||||||
interface WriteStandardKeyValueRepo<Key, Value> : Repo {
|
interface WriteStandardKeyValueRepo<Key, Value> : Repo {
|
||||||
val onNewValue: Flow<Pair<Key, Value>>
|
val onNewValue: Flow<Pair<Key, Value>>
|
||||||
@@ -19,6 +21,7 @@ interface WriteStandardKeyValueRepo<Key, Value> : Repo {
|
|||||||
suspend fun set(toSet: Map<Key, Value>)
|
suspend fun set(toSet: Map<Key, Value>)
|
||||||
suspend fun unset(toUnset: List<Key>)
|
suspend fun unset(toUnset: List<Key>)
|
||||||
}
|
}
|
||||||
|
typealias WriteKeyValueRepo<Key,Value> = WriteStandardKeyValueRepo<Key, Value>
|
||||||
|
|
||||||
suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.set(
|
suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.set(
|
||||||
vararg toSet: Pair<Key, Value>
|
vararg toSet: Pair<Key, Value>
|
||||||
@@ -32,4 +35,5 @@ suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.unset(
|
|||||||
vararg k: Key
|
vararg k: Key
|
||||||
) = unset(k.toList())
|
) = unset(k.toList())
|
||||||
|
|
||||||
interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value>, WriteStandardKeyValueRepo<Key, Value>
|
interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value>, WriteStandardKeyValueRepo<Key, Value>
|
||||||
|
typealias KeyValueRepo<Key,Value> = StandardKeyValueRepo<Key, Value>
|
||||||
|
@@ -44,6 +44,23 @@ open class MapperReadStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun keys(
|
||||||
|
v: FromValue,
|
||||||
|
pagination: Pagination,
|
||||||
|
reversed: Boolean
|
||||||
|
): PaginationResult<FromKey> = to.keys(
|
||||||
|
v.toOutValue(),
|
||||||
|
pagination,
|
||||||
|
reversed
|
||||||
|
).let {
|
||||||
|
PaginationResult(
|
||||||
|
it.page,
|
||||||
|
it.pagesNumber,
|
||||||
|
it.results.map { it.toInnerKey() },
|
||||||
|
it.size
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun contains(key: FromKey): Boolean = to.contains(
|
override suspend fun contains(key: FromKey): Boolean = to.contains(
|
||||||
key.toOutKey()
|
key.toOutKey()
|
||||||
)
|
)
|
||||||
@@ -51,6 +68,21 @@ open class MapperReadStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
|||||||
override suspend fun count(): Long = to.count()
|
override suspend fun count(): Long = to.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <FromKey, FromValue, ToKey, ToValue> ReadStandardKeyValueRepo<ToKey, ToValue>.withMapper(
|
||||||
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||||
|
): ReadStandardKeyValueRepo<FromKey, FromValue> = MapperReadStandardKeyValueRepo(this, mapper)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadStandardKeyValueRepo<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(
|
||||||
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
|
)
|
||||||
|
|
||||||
open class MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
open class MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
||||||
private val to: WriteStandardKeyValueRepo<ToKey, ToValue>,
|
private val to: WriteStandardKeyValueRepo<ToKey, ToValue>,
|
||||||
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||||
@@ -75,6 +107,21 @@ open class MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <FromKey, FromValue, ToKey, ToValue> WriteStandardKeyValueRepo<ToKey, ToValue>.withMapper(
|
||||||
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||||
|
): WriteStandardKeyValueRepo<FromKey, FromValue> = MapperWriteStandardKeyValueRepo(this, mapper)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteStandardKeyValueRepo<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(
|
||||||
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
|
)
|
||||||
|
|
||||||
open class MapperStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
open class MapperStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
||||||
private val to: StandardKeyValueRepo<ToKey, ToValue>,
|
private val to: StandardKeyValueRepo<ToKey, ToValue>,
|
||||||
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||||
@@ -82,3 +129,18 @@ open class MapperStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
|||||||
MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper,
|
MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper,
|
||||||
ReadStandardKeyValueRepo<FromKey, FromValue> by MapperReadStandardKeyValueRepo(to, mapper),
|
ReadStandardKeyValueRepo<FromKey, FromValue> by MapperReadStandardKeyValueRepo(to, mapper),
|
||||||
WriteStandardKeyValueRepo<FromKey, FromValue> by MapperWriteStandardKeyValueRepo(to, mapper)
|
WriteStandardKeyValueRepo<FromKey, FromValue> by MapperWriteStandardKeyValueRepo(to, mapper)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <FromKey, FromValue, ToKey, ToValue> StandardKeyValueRepo<ToKey, ToValue>.withMapper(
|
||||||
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||||
|
): StandardKeyValueRepo<FromKey, FromValue> = MapperStandardKeyValueRepo(this, mapper)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> StandardKeyValueRepo<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(
|
||||||
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
|
)
|
||||||
|
@@ -42,6 +42,23 @@ open class MapperReadOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun keys(
|
||||||
|
v: FromValue,
|
||||||
|
pagination: Pagination,
|
||||||
|
reversed: Boolean
|
||||||
|
): PaginationResult<FromKey> = to.keys(
|
||||||
|
v.toOutValue(),
|
||||||
|
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): Boolean = to.contains(k.toOutKey())
|
||||||
override suspend fun contains(k: FromKey, v: FromValue): Boolean = to.contains(k.toOutKey(), v.toOutValue())
|
override suspend fun contains(k: FromKey, v: FromValue): Boolean = to.contains(k.toOutKey(), v.toOutValue())
|
||||||
|
|
||||||
@@ -49,6 +66,21 @@ open class MapperReadOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
|||||||
override suspend fun count(k: FromKey): Long = to.count(k.toOutKey())
|
override suspend fun count(k: FromKey): Long = to.count(k.toOutKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <FromKey, FromValue, ToKey, ToValue> ReadOneToManyKeyValueRepo<ToKey, ToValue>.withMapper(
|
||||||
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||||
|
): ReadOneToManyKeyValueRepo<FromKey, FromValue> = MapperReadOneToManyKeyValueRepo(this, mapper)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadOneToManyKeyValueRepo<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(
|
||||||
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
|
)
|
||||||
|
|
||||||
open class MapperWriteOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
open class MapperWriteOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
||||||
private val to: WriteOneToManyKeyValueRepo<ToKey, ToValue>,
|
private val to: WriteOneToManyKeyValueRepo<ToKey, ToValue>,
|
||||||
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||||
@@ -75,9 +107,30 @@ open class MapperWriteOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
|||||||
}.toMap()
|
}.toMap()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override suspend fun set(toSet: Map<FromKey, List<FromValue>>) {
|
||||||
|
to.set(
|
||||||
|
toSet.map { (k, vs) -> k.toOutKey() to vs.map { v -> v.toOutValue() } }.toMap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun clear(k: FromKey) = to.clear(k.toOutKey())
|
override suspend fun clear(k: FromKey) = to.clear(k.toOutKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <FromKey, FromValue, ToKey, ToValue> WriteOneToManyKeyValueRepo<ToKey, ToValue>.withMapper(
|
||||||
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||||
|
): WriteOneToManyKeyValueRepo<FromKey, FromValue> = MapperWriteOneToManyKeyValueRepo(this, mapper)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteOneToManyKeyValueRepo<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(
|
||||||
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
|
)
|
||||||
|
|
||||||
open class MapperOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
open class MapperOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
||||||
private val to: OneToManyKeyValueRepo<ToKey, ToValue>,
|
private val to: OneToManyKeyValueRepo<ToKey, ToValue>,
|
||||||
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||||
@@ -85,3 +138,18 @@ open class MapperOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
|||||||
MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper,
|
MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper,
|
||||||
ReadOneToManyKeyValueRepo<FromKey, FromValue> by MapperReadOneToManyKeyValueRepo(to, mapper),
|
ReadOneToManyKeyValueRepo<FromKey, FromValue> by MapperReadOneToManyKeyValueRepo(to, mapper),
|
||||||
WriteOneToManyKeyValueRepo<FromKey, FromValue> by MapperWriteOneToManyKeyValueRepo(to, mapper)
|
WriteOneToManyKeyValueRepo<FromKey, FromValue> by MapperWriteOneToManyKeyValueRepo(to, mapper)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <FromKey, FromValue, ToKey, ToValue> OneToManyKeyValueRepo<ToKey, ToValue>.withMapper(
|
||||||
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||||
|
): OneToManyKeyValueRepo<FromKey, FromValue> = MapperOneToManyKeyValueRepo(this, mapper)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> OneToManyKeyValueRepo<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(
|
||||||
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
|
)
|
||||||
|
@@ -0,0 +1,13 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.versions
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
|
||||||
|
import dev.inmo.micro_utils.repos.set
|
||||||
|
|
||||||
|
class KeyValueBasedVersionsRepoProxy<T>(
|
||||||
|
private val keyValueStore: StandardKeyValueRepo<String, Int>,
|
||||||
|
override val database: T
|
||||||
|
) : StandardVersionsRepoProxy<T> {
|
||||||
|
override suspend fun getTableVersion(tableName: String): Int? = keyValueStore.get(tableName)
|
||||||
|
|
||||||
|
override suspend fun updateTableVersion(tableName: String, version: Int) { keyValueStore.set(tableName, version) }
|
||||||
|
}
|
@@ -0,0 +1,36 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.versions
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.repos.Repo
|
||||||
|
|
||||||
|
interface StandardVersionsRepoProxy<T> : Repo {
|
||||||
|
val database: T
|
||||||
|
|
||||||
|
suspend fun getTableVersion(tableName: String): Int?
|
||||||
|
suspend fun updateTableVersion(tableName: String, version: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
class StandardVersionsRepo<T>(
|
||||||
|
private val proxy: StandardVersionsRepoProxy<T>
|
||||||
|
) : VersionsRepo<T> {
|
||||||
|
override suspend fun setTableVersion(
|
||||||
|
tableName: String,
|
||||||
|
version: Int,
|
||||||
|
onCreate: suspend T.() -> Unit,
|
||||||
|
onUpdate: suspend T.(from: Int, to: Int) -> Unit
|
||||||
|
) {
|
||||||
|
var savedVersion = proxy.getTableVersion(tableName)
|
||||||
|
if (savedVersion == null) {
|
||||||
|
proxy.database.onCreate()
|
||||||
|
proxy.updateTableVersion(tableName, version)
|
||||||
|
} else {
|
||||||
|
while (savedVersion != null && savedVersion < version) {
|
||||||
|
val newVersion = savedVersion + 1
|
||||||
|
|
||||||
|
proxy.database.onUpdate(savedVersion, newVersion)
|
||||||
|
|
||||||
|
proxy.updateTableVersion(tableName, newVersion)
|
||||||
|
savedVersion = newVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,31 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.versions
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.repos.Repo
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface has been created due to requirement to work with different versions of databases and make some
|
||||||
|
* migrations between versions
|
||||||
|
*
|
||||||
|
* @param T It is a type of database, which will be used by this repo to retrieve current table version and update it
|
||||||
|
*/
|
||||||
|
interface VersionsRepo<T> : Repo {
|
||||||
|
/**
|
||||||
|
* By default, instance of this interface will check that version of table with name [tableName] is less than
|
||||||
|
* [version] or is absent
|
||||||
|
*
|
||||||
|
* * In case if [tableName] didn't found, will be called [onCreate] and version of table will be set up to [version]
|
||||||
|
* * In case if [tableName] have version less than parameter [version], it will increase version one-by-one
|
||||||
|
* until database version will be equal to [version]
|
||||||
|
*
|
||||||
|
* @param version Current version of table
|
||||||
|
* @param onCreate This callback will be called in case when table have no information about table
|
||||||
|
* @param onUpdate This callback will be called after **iterative** changing of version. It is expected that parameter
|
||||||
|
* "to" will always be greater than "from"
|
||||||
|
*/
|
||||||
|
suspend fun setTableVersion(
|
||||||
|
tableName: String,
|
||||||
|
version: Int,
|
||||||
|
onCreate: suspend T.() -> Unit = {},
|
||||||
|
onUpdate: suspend T.(from: Int, to: Int) -> Unit = { _, _ ->}
|
||||||
|
)
|
||||||
|
}
|
@@ -0,0 +1,171 @@
|
|||||||
|
package dev.inmo.micro_utils.repos
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.Warning
|
||||||
|
import dev.inmo.micro_utils.pagination.*
|
||||||
|
import dev.inmo.micro_utils.pagination.utils.reverse
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.coroutines.flow.*
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.file.FileSystems
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.StandardWatchEventKinds.*
|
||||||
|
|
||||||
|
private inline val String.isAbsolute
|
||||||
|
get() = startsWith(File.separator)
|
||||||
|
|
||||||
|
class FileReadStandardKeyValueRepo(
|
||||||
|
private val folder: File
|
||||||
|
) : ReadStandardKeyValueRepo<String, File> {
|
||||||
|
init {
|
||||||
|
folder.mkdirs()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun get(k: String): File? {
|
||||||
|
val file = File(folder, k)
|
||||||
|
if (file.exists()) {
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<File> {
|
||||||
|
val count = count()
|
||||||
|
val resultPagination = if (reversed) pagination.reverse(count) else pagination
|
||||||
|
val filesPaths = folder.list() ?.copyOfRange(resultPagination.firstIndex, resultPagination.lastIndex) ?: return emptyPaginationResult()
|
||||||
|
if (reversed) {
|
||||||
|
filesPaths.reverse()
|
||||||
|
}
|
||||||
|
return filesPaths.map { File(folder, it) }.createPaginationResult(
|
||||||
|
resultPagination,
|
||||||
|
count
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<String> {
|
||||||
|
val count = count()
|
||||||
|
val resultPagination = if (reversed) pagination.reverse(count) else pagination
|
||||||
|
val filesPaths = folder.list() ?.copyOfRange(resultPagination.firstIndex, resultPagination.lastIndex) ?: return emptyPaginationResult()
|
||||||
|
if (reversed) {
|
||||||
|
filesPaths.reverse()
|
||||||
|
}
|
||||||
|
return filesPaths.toList().createPaginationResult(
|
||||||
|
resultPagination,
|
||||||
|
count
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun keys(
|
||||||
|
v: File,
|
||||||
|
pagination: Pagination,
|
||||||
|
reversed: Boolean
|
||||||
|
): PaginationResult<String> {
|
||||||
|
val resultPagination = if (reversed) pagination.reverse(1L) else pagination
|
||||||
|
return if (resultPagination.isFirstPage) {
|
||||||
|
val fileSubpath = v.absolutePath.removePrefix(folder.absolutePath)
|
||||||
|
if (fileSubpath == v.absolutePath) {
|
||||||
|
emptyList()
|
||||||
|
} else {
|
||||||
|
listOf(fileSubpath)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}.createPaginationResult(resultPagination, 1L)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun contains(key: String): Boolean {
|
||||||
|
return File(folder, key).exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun count(): Long = folder.list() ?.size ?.toLong() ?: 0L
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(
|
||||||
|
private val folder: File,
|
||||||
|
filesChangedProcessingScope: CoroutineScope? = null
|
||||||
|
) : WriteStandardKeyValueRepo<String, File> {
|
||||||
|
private val _onNewValue = MutableSharedFlow<Pair<String, File>>()
|
||||||
|
override val onNewValue: Flow<Pair<String, File>> = _onNewValue.asSharedFlow()
|
||||||
|
private val _onValueRemoved = MutableSharedFlow<String>()
|
||||||
|
override val onValueRemoved: Flow<String> = _onValueRemoved.asSharedFlow()
|
||||||
|
|
||||||
|
init {
|
||||||
|
folder.mkdirs()
|
||||||
|
filesChangedProcessingScope ?.let {
|
||||||
|
it.launch {
|
||||||
|
try {
|
||||||
|
val folderPath = folder.toPath()
|
||||||
|
while (isActive) {
|
||||||
|
val key = try {
|
||||||
|
folderPath.register(FileSystems.getDefault().newWatchService(), ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// add verbose way to show that file watching is not working
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
|
||||||
|
for (event in key.pollEvents()) {
|
||||||
|
val relativeFilePath = (event.context() as? Path) ?: continue
|
||||||
|
val file = relativeFilePath.toFile()
|
||||||
|
val relativePath = file.toRelativeString(folder)
|
||||||
|
|
||||||
|
when (event.kind()) {
|
||||||
|
ENTRY_CREATE, ENTRY_MODIFY -> {
|
||||||
|
launch {
|
||||||
|
_onNewValue.emit(relativePath to file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ENTRY_DELETE -> {
|
||||||
|
launch {
|
||||||
|
_onValueRemoved.emit(relativePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.isValid || folder.exists()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
// add verbose way to notify that this functionality is disabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun set(toSet: Map<String, File>) {
|
||||||
|
supervisorScope {
|
||||||
|
toSet.map { (filename, fileSource) ->
|
||||||
|
launch {
|
||||||
|
val file = File(folder, filename)
|
||||||
|
|
||||||
|
file.delete()
|
||||||
|
fileSource.copyTo(file, overwrite = true)
|
||||||
|
_onNewValue.emit(filename to file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.joinAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun unset(toUnset: List<String>) {
|
||||||
|
toUnset.forEach {
|
||||||
|
val file = File(folder, it)
|
||||||
|
if (file.exists()) {
|
||||||
|
file.delete()
|
||||||
|
_onValueRemoved.emit(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Warning("Files watching will not correctly works on Android Platform with version of API lower than API 26")
|
||||||
|
class FileStandardKeyValueRepo(
|
||||||
|
folder: File,
|
||||||
|
filesChangedProcessingScope: CoroutineScope? = null
|
||||||
|
) : StandardKeyValueRepo<String, File>,
|
||||||
|
WriteStandardKeyValueRepo<String, File> by FileWriteStandardKeyValueRepo(folder, filesChangedProcessingScope),
|
||||||
|
ReadStandardKeyValueRepo<String, File> by FileReadStandardKeyValueRepo(folder)
|
@@ -1,6 +1,6 @@
|
|||||||
package dev.inmo.micro_utils.repos
|
package dev.inmo.micro_utils.repos
|
||||||
|
|
||||||
import kotlinx.coroutines.newSingleThreadContext
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
val DatabaseCoroutineContext: CoroutineContext = newSingleThreadContext("db-context")
|
val DatabaseCoroutineContext: CoroutineContext = Dispatchers.IO
|
||||||
|
@@ -2,26 +2,68 @@ package dev.inmo.micro_utils.repos
|
|||||||
|
|
||||||
import android.database.sqlite.SQLiteDatabase
|
import android.database.sqlite.SQLiteDatabase
|
||||||
import dev.inmo.micro_utils.coroutines.safely
|
import dev.inmo.micro_utils.coroutines.safely
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
|
private object ContextsPool {
|
||||||
|
private val contexts = mutableListOf<CoroutineContext>()
|
||||||
|
private val mutex = Mutex(locked = false)
|
||||||
|
private val freeContexts = mutableListOf<CoroutineContext>()
|
||||||
|
|
||||||
|
suspend fun acquireContext(): CoroutineContext {
|
||||||
|
return mutex.withLock {
|
||||||
|
freeContexts.removeFirstOrNull() ?: Executors.newSingleThreadExecutor().asCoroutineDispatcher().also {
|
||||||
|
contexts.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun freeContext(context: CoroutineContext) {
|
||||||
|
return mutex.withLock {
|
||||||
|
if (context in contexts && context !in freeContexts) {
|
||||||
|
freeContexts.add(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun <T> use(block: suspend (CoroutineContext) -> T): T = acquireContext().let {
|
||||||
|
try {
|
||||||
|
block(it)
|
||||||
|
} finally {
|
||||||
|
freeContext(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TransactionContext(
|
||||||
|
val databaseContext: CoroutineContext
|
||||||
|
): CoroutineContext.Element {
|
||||||
|
override val key: CoroutineContext.Key<TransactionContext> = TransactionContext
|
||||||
|
|
||||||
|
companion object : CoroutineContext.Key<TransactionContext>
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun <T> SQLiteDatabase.transaction(block: suspend SQLiteDatabase.() -> T): T {
|
suspend fun <T> SQLiteDatabase.transaction(block: suspend SQLiteDatabase.() -> T): T {
|
||||||
return withContext(DatabaseCoroutineContext) {
|
return coroutineContext[TransactionContext] ?.let {
|
||||||
when {
|
withContext(it.databaseContext) {
|
||||||
inTransaction() -> {
|
block()
|
||||||
block()
|
}
|
||||||
}
|
} ?: ContextsPool.use { context ->
|
||||||
else -> {
|
withContext(TransactionContext(context) + context) {
|
||||||
beginTransaction()
|
beginTransaction()
|
||||||
safely(
|
safely(
|
||||||
{
|
{
|
||||||
endTransaction()
|
endTransaction()
|
||||||
throw it
|
throw it
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
block().also {
|
block().also {
|
||||||
setTransactionSuccessful()
|
setTransactionSuccessful()
|
||||||
endTransaction()
|
endTransaction()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ import android.database.DatabaseErrorHandler
|
|||||||
import android.database.sqlite.SQLiteDatabase
|
import android.database.sqlite.SQLiteDatabase
|
||||||
import android.database.sqlite.SQLiteOpenHelper
|
import android.database.sqlite.SQLiteOpenHelper
|
||||||
import dev.inmo.micro_utils.coroutines.safely
|
import dev.inmo.micro_utils.coroutines.safely
|
||||||
|
import dev.inmo.micro_utils.repos.versions.*
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.resumeWithException
|
import kotlin.coroutines.resumeWithException
|
||||||
@@ -36,6 +37,9 @@ class StandardSQLHelper(
|
|||||||
|
|
||||||
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {}
|
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {}
|
||||||
}
|
}
|
||||||
|
val versionsRepo: VersionsRepo<SQLiteOpenHelper> by lazy {
|
||||||
|
StandardVersionsRepo(AndroidSQLStandardVersionsRepoProxy(sqlOpenHelper))
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun <T> writableTransaction(block: suspend SQLiteDatabase.() -> T): T = sqlOpenHelper.writableTransaction(block)
|
suspend fun <T> writableTransaction(block: suspend SQLiteDatabase.() -> T): T = sqlOpenHelper.writableTransaction(block)
|
||||||
|
|
||||||
|
@@ -96,6 +96,20 @@ class KeyValueStore<T : Any> internal constructor (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun keys(v: T, pagination: Pagination, reversed: Boolean): PaginationResult<String> {
|
||||||
|
val resultPagination = if (reversed) pagination.reverse(count()) else pagination
|
||||||
|
return sharedPreferences.all.mapNotNull { (k, value) -> if (value == v) k else null }.paginate(
|
||||||
|
resultPagination
|
||||||
|
).let {
|
||||||
|
PaginationResult(
|
||||||
|
it.page,
|
||||||
|
it.pagesNumber,
|
||||||
|
it.results.let { if (reversed) it.reversed() else it },
|
||||||
|
it.size
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun contains(key: String): Boolean = sharedPreferences.contains(key)
|
override suspend fun contains(key: String): Boolean = sharedPreferences.contains(key)
|
||||||
|
|
||||||
override suspend fun count(): Long = sharedPreferences.all.size.toLong()
|
override suspend fun count(): Long = sharedPreferences.all.size.toLong()
|
||||||
|
@@ -87,6 +87,29 @@ class OneToManyAndroidRepo<Key, Value>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun set(toSet: Map<Key, List<Value>>) {
|
||||||
|
val (clearedKeys, inserted) = helper.writableTransaction {
|
||||||
|
toSet.mapNotNull { (k, _) ->
|
||||||
|
if (delete(tableName, "$idColumnName=?", arrayOf(k.asId())) > 0) {
|
||||||
|
k
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} to toSet.flatMap { (k, values) ->
|
||||||
|
values.map { v ->
|
||||||
|
insert(
|
||||||
|
tableName,
|
||||||
|
null,
|
||||||
|
contentValuesOf(idColumnName to k.asId(), valueColumnName to v.asValue())
|
||||||
|
)
|
||||||
|
k to v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearedKeys.forEach { _onDataCleared.emit(it) }
|
||||||
|
inserted.forEach { newPair -> _onNewValue.emit(newPair) }
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun contains(k: Key): Boolean = helper.readableTransaction {
|
override suspend fun contains(k: Key): Boolean = helper.readableTransaction {
|
||||||
select(tableName, selection = "$idColumnName=?", selectionArgs = arrayOf(k.asId()), limit = FirstPagePagination(1).limitClause()).use {
|
select(tableName, selection = "$idColumnName=?", selectionArgs = arrayOf(k.asId()), limit = FirstPagePagination(1).limitClause()).use {
|
||||||
it.count > 0
|
it.count > 0
|
||||||
@@ -169,6 +192,33 @@ class OneToManyAndroidRepo<Key, Value>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun keys(
|
||||||
|
v: Value,
|
||||||
|
pagination: Pagination,
|
||||||
|
reversed: Boolean
|
||||||
|
): PaginationResult<Key> = count().let { count ->
|
||||||
|
val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
|
||||||
|
helper.readableTransaction {
|
||||||
|
select(
|
||||||
|
tableName,
|
||||||
|
selection = "$valueColumnName=?",
|
||||||
|
selectionArgs = arrayOf(v.asValue()),
|
||||||
|
limit = resultPagination.limitClause()
|
||||||
|
).use { c ->
|
||||||
|
mutableListOf<Key>().also {
|
||||||
|
if (c.moveToFirst()) {
|
||||||
|
do {
|
||||||
|
it.add(c.getString(idColumnName).asKey())
|
||||||
|
} while (c.moveToNext())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.createPaginationResult(
|
||||||
|
pagination,
|
||||||
|
count
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun remove(toRemove: Map<Key, List<Value>>) {
|
override suspend fun remove(toRemove: Map<Key, List<Value>>) {
|
||||||
helper.writableTransaction {
|
helper.writableTransaction {
|
||||||
toRemove.flatMap { (k, vs) ->
|
toRemove.flatMap { (k, vs) ->
|
||||||
|
@@ -0,0 +1,63 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.versions
|
||||||
|
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper
|
||||||
|
import androidx.core.content.contentValuesOf
|
||||||
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [VersionsRepo] based on [SQLiteOpenHelper] with table inside of [database]
|
||||||
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun versionsRepo(database: SQLiteOpenHelper): VersionsRepo<SQLiteOpenHelper> = StandardVersionsRepo(
|
||||||
|
AndroidSQLStandardVersionsRepoProxy(database)
|
||||||
|
)
|
||||||
|
|
||||||
|
class AndroidSQLStandardVersionsRepoProxy(
|
||||||
|
override val database: SQLiteOpenHelper
|
||||||
|
) : StandardVersionsRepoProxy<SQLiteOpenHelper> {
|
||||||
|
private val tableName: String = "AndroidSQLStandardVersionsRepo"
|
||||||
|
private val tableNameColumnName = "tableName"
|
||||||
|
private val tableVersionColumnName = "version"
|
||||||
|
|
||||||
|
init {
|
||||||
|
runBlocking(DatabaseCoroutineContext) {
|
||||||
|
database.writableTransaction {
|
||||||
|
createTable(
|
||||||
|
tableName,
|
||||||
|
tableNameColumnName to ColumnType.Text.NOT_NULLABLE,
|
||||||
|
tableVersionColumnName to ColumnType.Numeric.INTEGER()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getTableVersion(table: String): Int? = database.writableTransaction {
|
||||||
|
select(
|
||||||
|
tableName,
|
||||||
|
selection = "$tableNameColumnName=?",
|
||||||
|
selectionArgs = arrayOf(table),
|
||||||
|
limit = limitClause(1)
|
||||||
|
).use {
|
||||||
|
if (it.moveToFirst()) {
|
||||||
|
it.getInt(tableVersionColumnName)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateTableVersion(table: String, version: Int) {
|
||||||
|
database.writableTransaction {
|
||||||
|
val updated = update(
|
||||||
|
tableName,
|
||||||
|
contentValuesOf(tableVersionColumnName to version),
|
||||||
|
"$tableNameColumnName=?",
|
||||||
|
arrayOf(table)
|
||||||
|
) > 0
|
||||||
|
if (!updated) {
|
||||||
|
insert(tableName, null, contentValuesOf(tableNameColumnName to table, tableVersionColumnName to version))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,49 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE")
|
||||||
|
|
||||||
|
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]
|
||||||
|
*
|
||||||
|
* @receiver Will be used to create [KeyValueBasedVersionsRepoProxy] via [keyValueStore] and pass it to [StandardVersionsRepo]
|
||||||
|
*
|
||||||
|
* @see [KeyValueBasedVersionsRepoProxy]
|
||||||
|
* @see [keyValueStore]
|
||||||
|
*/
|
||||||
|
inline fun <T> Context.versionsKeyValueRepo(
|
||||||
|
database: T
|
||||||
|
): VersionsRepo<T> = StandardVersionsRepo(
|
||||||
|
KeyValueBasedVersionsRepoProxy(
|
||||||
|
keyValueStore("SPVersionsRepo"),
|
||||||
|
database
|
||||||
|
)
|
||||||
|
)
|
||||||
|
/**
|
||||||
|
* Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [StandardKeyValueRepo]
|
||||||
|
*
|
||||||
|
* @receiver Will be used to create [StandardKeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo]
|
||||||
|
*
|
||||||
|
* @see [keyValueStore]
|
||||||
|
*/
|
||||||
|
inline fun Context.versionsKeyValueRepoForSQL(
|
||||||
|
database: SQLiteOpenHelper
|
||||||
|
) = versionsKeyValueRepo(database)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [StandardKeyValueRepo]
|
||||||
|
*
|
||||||
|
* @param context Will be used to create [StandardKeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo]
|
||||||
|
*
|
||||||
|
* @see [keyValueStore]
|
||||||
|
*/
|
||||||
|
inline fun versionsRepo(
|
||||||
|
context: Context,
|
||||||
|
database: SQLiteOpenHelper
|
||||||
|
) = context.versionsKeyValueRepoForSQL(database)
|
@@ -2,6 +2,7 @@ package dev.inmo.micro_utils.repos.exposed.keyvalue
|
|||||||
|
|
||||||
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
|
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
|
||||||
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
|
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
|
||||||
|
import dev.inmo.micro_utils.repos.exposed.initTable
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
@@ -18,8 +19,8 @@ open class ExposedKeyValueRepo<Key, Value>(
|
|||||||
valueColumnAllocator,
|
valueColumnAllocator,
|
||||||
tableName
|
tableName
|
||||||
) {
|
) {
|
||||||
private val _onNewValue = MutableSharedFlow<Pair<Key, Value>>(Channel.BUFFERED)
|
private val _onNewValue = MutableSharedFlow<Pair<Key, Value>>()
|
||||||
private val _onValueRemoved = MutableSharedFlow<Key>(Channel.BUFFERED)
|
private val _onValueRemoved = MutableSharedFlow<Key>()
|
||||||
|
|
||||||
override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow()
|
override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow()
|
||||||
override val onValueRemoved: Flow<Key> = _onValueRemoved.asSharedFlow()
|
override val onValueRemoved: Flow<Key> = _onValueRemoved.asSharedFlow()
|
||||||
|
@@ -2,8 +2,7 @@ package dev.inmo.micro_utils.repos.exposed.keyvalue
|
|||||||
|
|
||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
|
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
|
||||||
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
|
import dev.inmo.micro_utils.repos.exposed.*
|
||||||
import dev.inmo.micro_utils.repos.exposed.ExposedRepo
|
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
|
||||||
@@ -17,6 +16,8 @@ open class ExposedReadKeyValueRepo<Key, Value>(
|
|||||||
protected val valueColumn: Column<Value> = valueColumnAllocator()
|
protected val valueColumn: Column<Value> = valueColumnAllocator()
|
||||||
override val primaryKey: PrimaryKey = PrimaryKey(keyColumn, valueColumn)
|
override val primaryKey: PrimaryKey = PrimaryKey(keyColumn, valueColumn)
|
||||||
|
|
||||||
|
init { initTable() }
|
||||||
|
|
||||||
override suspend fun get(k: Key): Value? = transaction(database) {
|
override suspend fun get(k: Key): Value? = transaction(database) {
|
||||||
select { keyColumn.eq(k) }.limit(1).firstOrNull() ?.getOrNull(valueColumn)
|
select { keyColumn.eq(k) }.limit(1).firstOrNull() ?.getOrNull(valueColumn)
|
||||||
}
|
}
|
||||||
@@ -33,6 +34,16 @@ open class ExposedReadKeyValueRepo<Key, Value>(
|
|||||||
}
|
}
|
||||||
}.createPaginationResult(pagination, count())
|
}.createPaginationResult(pagination, count())
|
||||||
|
|
||||||
|
override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> = transaction(database) {
|
||||||
|
select { valueColumn.eq(v) }.let {
|
||||||
|
it.count() to it.paginate(pagination, keyColumn to if (reversed) SortOrder.DESC else SortOrder.ASC).map {
|
||||||
|
it[keyColumn]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.let { (count, list) ->
|
||||||
|
list.createPaginationResult(pagination, count)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> = transaction(database) {
|
override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> = transaction(database) {
|
||||||
selectAll().paginate(pagination, keyColumn to if (reversed) SortOrder.DESC else SortOrder.ASC).map {
|
selectAll().paginate(pagination, keyColumn to if (reversed) SortOrder.DESC else SortOrder.ASC).map {
|
||||||
it[valueColumn]
|
it[valueColumn]
|
||||||
|
@@ -39,6 +39,21 @@ open class ExposedReadOneToManyKeyValueRepo<Key, Value>(
|
|||||||
count()
|
count()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override suspend fun keys(
|
||||||
|
v: Value,
|
||||||
|
pagination: Pagination,
|
||||||
|
reversed: Boolean
|
||||||
|
): PaginationResult<Key> = transaction(database) {
|
||||||
|
select { valueColumn.eq(v) }.let {
|
||||||
|
it.count() to it.paginate(pagination, keyColumn, reversed).map { it[keyColumn] }
|
||||||
|
}
|
||||||
|
}.let { (count, list) ->
|
||||||
|
list.createPaginationResult(
|
||||||
|
pagination,
|
||||||
|
count
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun contains(k: Key): Boolean = transaction(database) {
|
override suspend fun contains(k: Key): Boolean = transaction(database) {
|
||||||
select { keyColumn.eq(k) }.limit(1).any()
|
select { keyColumn.eq(k) }.limit(1).any()
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,48 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.exposed.versions
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.repos.exposed.ExposedRepo
|
||||||
|
import dev.inmo.micro_utils.repos.exposed.initTable
|
||||||
|
import dev.inmo.micro_utils.repos.versions.*
|
||||||
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this method to create [StandardVersionsRepo] based on [Database] with [ExposedStandardVersionsRepoProxy] as
|
||||||
|
* [StandardVersionsRepoProxy]
|
||||||
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun versionsRepo(database: Database): VersionsRepo<Database> = StandardVersionsRepo(
|
||||||
|
ExposedStandardVersionsRepoProxy(database)
|
||||||
|
)
|
||||||
|
|
||||||
|
class ExposedStandardVersionsRepoProxy(
|
||||||
|
override val database: Database
|
||||||
|
) : StandardVersionsRepoProxy<Database>, Table("ExposedVersionsProxy"), ExposedRepo {
|
||||||
|
private val tableNameColumn = text("tableName")
|
||||||
|
private val tableVersionColumn = integer("tableName")
|
||||||
|
|
||||||
|
init {
|
||||||
|
initTable()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getTableVersion(tableName: String): Int? = transaction(database) {
|
||||||
|
select { tableNameColumn.eq(tableName) }.limit(1).firstOrNull() ?.getOrNull(tableVersionColumn)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateTableVersion(tableName: String, version: Int) {
|
||||||
|
transaction(database) {
|
||||||
|
val updated = update(
|
||||||
|
{ tableNameColumn.eq(tableName) }
|
||||||
|
) {
|
||||||
|
it[tableVersionColumn] = version
|
||||||
|
} > 0
|
||||||
|
if (!updated) {
|
||||||
|
insert {
|
||||||
|
it[tableNameColumn] = tableName
|
||||||
|
it[tableVersionColumn] = version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
@@ -39,6 +39,18 @@ class ReadMapKeyValueRepo<Key, Value>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
|
||||||
|
val keys: List<Key> = map.mapNotNull { (k, value) -> if (v == value) k else null }
|
||||||
|
val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination
|
||||||
|
return keys.paginate(actualPagination).let {
|
||||||
|
if (reversed) {
|
||||||
|
it.copy(results = it.results.reversed())
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun contains(key: Key): Boolean = map.containsKey(key)
|
override suspend fun contains(key: Key): Boolean = map.containsKey(key)
|
||||||
|
|
||||||
override suspend fun count(): Long = map.size.toLong()
|
override suspend fun count(): Long = map.size.toLong()
|
||||||
|
@@ -32,6 +32,18 @@ class MapReadOneToManyKeyValueRepo<Key, Value>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
|
||||||
|
val keys = map.keys.filter { map[it] ?.contains(v) == true }
|
||||||
|
val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination
|
||||||
|
return keys.paginate(actualPagination).let {
|
||||||
|
if (reversed) {
|
||||||
|
it.copy(results = it.results.reversed())
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun contains(k: Key): Boolean = map.containsKey(k)
|
override suspend fun contains(k: Key): Boolean = map.containsKey(k)
|
||||||
|
|
||||||
override suspend fun contains(k: Key, v: Value): Boolean = map[k] ?.contains(v) == true
|
override suspend fun contains(k: Key, v: Value): Boolean = map[k] ?.contains(v) == true
|
||||||
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
@@ -1,8 +1,7 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.crud
|
package dev.inmo.micro_utils.repos.ktor.client.crud
|
||||||
|
|
||||||
import dev.inmo.micro_utils.ktor.client.encodeUrlQueryValue
|
import dev.inmo.micro_utils.ktor.client.*
|
||||||
import dev.inmo.micro_utils.ktor.client.uniget
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
|
||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
@@ -12,41 +11,52 @@ import kotlinx.serialization.builtins.serializer
|
|||||||
|
|
||||||
class KtorReadStandardCrudRepo<ObjectType, IdType> (
|
class KtorReadStandardCrudRepo<ObjectType, IdType> (
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val client: HttpClient = HttpClient(),
|
private val unifiedRequester: UnifiedRequester,
|
||||||
private val objectsSerializer: KSerializer<ObjectType>,
|
private val objectsSerializer: KSerializer<ObjectType>,
|
||||||
private val objectsSerializerNullable: KSerializer<ObjectType?>,
|
private val objectsSerializerNullable: KSerializer<ObjectType?>,
|
||||||
private val idsSerializer: KSerializer<IdType>
|
private val idsSerializer: KSerializer<IdType>
|
||||||
) : ReadStandardCRUDRepo<ObjectType, IdType> {
|
) : ReadStandardCRUDRepo<ObjectType, IdType> {
|
||||||
private val paginationResultSerializer = PaginationResult.serializer(objectsSerializer)
|
private val paginationResultSerializer = PaginationResult.serializer(objectsSerializer)
|
||||||
|
|
||||||
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = client.uniget(
|
constructor(
|
||||||
|
baseUrl: String,
|
||||||
|
client: HttpClient,
|
||||||
|
objectsSerializer: KSerializer<ObjectType>,
|
||||||
|
objectsSerializerNullable: KSerializer<ObjectType?>,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
|
) : this (
|
||||||
|
baseUrl, UnifiedRequester(client, serialFormat), objectsSerializer, objectsSerializerNullable, idsSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = unifiedRequester.uniget(
|
||||||
buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts),
|
buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts),
|
||||||
paginationResultSerializer
|
paginationResultSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getById(id: IdType): ObjectType? = client.uniget(
|
override suspend fun getById(id: IdType): ObjectType? = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
getByIdRouting,
|
getByIdRouting,
|
||||||
mapOf(
|
mapOf(
|
||||||
"id" to idsSerializer.encodeUrlQueryValue(id)
|
"id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
objectsSerializerNullable
|
objectsSerializerNullable
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun contains(id: IdType): Boolean = client.uniget(
|
override suspend fun contains(id: IdType): Boolean = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
containsRouting,
|
containsRouting,
|
||||||
mapOf(
|
mapOf(
|
||||||
"id" to idsSerializer.encodeUrlQueryValue(id)
|
"id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
Boolean.serializer()
|
Boolean.serializer()
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun count(): Long = client.uniget(
|
override suspend fun count(): Long = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
countRouting
|
countRouting
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.crud
|
package dev.inmo.micro_utils.repos.ktor.client.crud
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.client.UnifiedRequester
|
||||||
|
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
|
||||||
|
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
@@ -7,7 +10,7 @@ import kotlinx.serialization.KSerializer
|
|||||||
class KtorStandardCrudRepo<ObjectType, IdType, InputValue> (
|
class KtorStandardCrudRepo<ObjectType, IdType, InputValue> (
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
baseSubpart: String,
|
baseSubpart: String,
|
||||||
client: HttpClient,
|
unifiedRequester: UnifiedRequester,
|
||||||
objectsSerializer: KSerializer<ObjectType>,
|
objectsSerializer: KSerializer<ObjectType>,
|
||||||
objectsNullableSerializer: KSerializer<ObjectType?>,
|
objectsNullableSerializer: KSerializer<ObjectType?>,
|
||||||
inputsSerializer: KSerializer<InputValue>,
|
inputsSerializer: KSerializer<InputValue>,
|
||||||
@@ -15,16 +18,29 @@ class KtorStandardCrudRepo<ObjectType, IdType, InputValue> (
|
|||||||
) : StandardCRUDRepo<ObjectType, IdType, InputValue>,
|
) : StandardCRUDRepo<ObjectType, IdType, InputValue>,
|
||||||
ReadStandardCRUDRepo<ObjectType, IdType> by KtorReadStandardCrudRepo(
|
ReadStandardCRUDRepo<ObjectType, IdType> by KtorReadStandardCrudRepo(
|
||||||
"$baseUrl/$baseSubpart",
|
"$baseUrl/$baseSubpart",
|
||||||
client,
|
unifiedRequester,
|
||||||
objectsSerializer,
|
objectsSerializer,
|
||||||
objectsNullableSerializer,
|
objectsNullableSerializer,
|
||||||
idsSerializer
|
idsSerializer
|
||||||
),
|
),
|
||||||
WriteStandardCRUDRepo<ObjectType, IdType, InputValue> by KtorWriteStandardCrudRepo(
|
WriteStandardCRUDRepo<ObjectType, IdType, InputValue> by KtorWriteStandardCrudRepo(
|
||||||
"$baseUrl/$baseSubpart",
|
"$baseUrl/$baseSubpart",
|
||||||
client,
|
unifiedRequester,
|
||||||
objectsSerializer,
|
objectsSerializer,
|
||||||
objectsNullableSerializer,
|
objectsNullableSerializer,
|
||||||
inputsSerializer,
|
inputsSerializer,
|
||||||
idsSerializer
|
idsSerializer
|
||||||
|
) {
|
||||||
|
constructor(
|
||||||
|
baseUrl: String,
|
||||||
|
baseSubpart: String,
|
||||||
|
client: HttpClient,
|
||||||
|
objectsSerializer: KSerializer<ObjectType>,
|
||||||
|
objectsNullableSerializer: KSerializer<ObjectType?>,
|
||||||
|
inputsSerializer: KSerializer<InputValue>,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
|
) : this(
|
||||||
|
baseUrl, baseSubpart, UnifiedRequester(client, serialFormat), objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.crud
|
package dev.inmo.micro_utils.repos.ktor.client.crud
|
||||||
|
|
||||||
import dev.inmo.micro_utils.ktor.client.*
|
import dev.inmo.micro_utils.ktor.client.*
|
||||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
import dev.inmo.micro_utils.repos.UpdatedValuePair
|
import dev.inmo.micro_utils.repos.UpdatedValuePair
|
||||||
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
|
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
@@ -12,7 +12,7 @@ import kotlinx.serialization.builtins.*
|
|||||||
|
|
||||||
class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
|
class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val client: HttpClient = HttpClient(),
|
private val unifiedRequester: UnifiedRequester,
|
||||||
private val objectsSerializer: KSerializer<ObjectType>,
|
private val objectsSerializer: KSerializer<ObjectType>,
|
||||||
private val objectsNullableSerializer: KSerializer<ObjectType?>,
|
private val objectsNullableSerializer: KSerializer<ObjectType?>,
|
||||||
private val inputsSerializer: KSerializer<InputValue>,
|
private val inputsSerializer: KSerializer<InputValue>,
|
||||||
@@ -27,39 +27,51 @@ class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
|
|||||||
)
|
)
|
||||||
private val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer)
|
private val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer)
|
||||||
|
|
||||||
override val newObjectsFlow: Flow<ObjectType> = client.createStandardWebsocketFlow(
|
constructor(
|
||||||
|
baseUrl: String,
|
||||||
|
client: HttpClient,
|
||||||
|
objectsSerializer: KSerializer<ObjectType>,
|
||||||
|
objectsSerializerNullable: KSerializer<ObjectType?>,
|
||||||
|
inputsSerializer: KSerializer<InputValue>,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
|
) : this (
|
||||||
|
baseUrl, UnifiedRequester(client, serialFormat), objectsSerializer, objectsSerializerNullable, inputsSerializer, idsSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
override val newObjectsFlow: Flow<ObjectType> = unifiedRequester.createStandardWebsocketFlow(
|
||||||
buildStandardUrl(baseUrl, newObjectsFlowRouting),
|
buildStandardUrl(baseUrl, newObjectsFlowRouting),
|
||||||
deserializer = objectsSerializer
|
deserializer = objectsSerializer
|
||||||
)
|
)
|
||||||
override val updatedObjectsFlow: Flow<ObjectType> = client.createStandardWebsocketFlow(
|
override val updatedObjectsFlow: Flow<ObjectType> = unifiedRequester.createStandardWebsocketFlow(
|
||||||
buildStandardUrl(baseUrl, updatedObjectsFlowRouting),
|
buildStandardUrl(baseUrl, updatedObjectsFlowRouting),
|
||||||
deserializer = objectsSerializer
|
deserializer = objectsSerializer
|
||||||
)
|
)
|
||||||
override val deletedObjectsIdsFlow: Flow<IdType> = client.createStandardWebsocketFlow(
|
override val deletedObjectsIdsFlow: Flow<IdType> = unifiedRequester.createStandardWebsocketFlow(
|
||||||
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting),
|
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting),
|
||||||
deserializer = idsSerializer
|
deserializer = idsSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
override suspend fun create(values: List<InputValue>): List<ObjectType> = client.unipost(
|
override suspend fun create(values: List<InputValue>): List<ObjectType> = unifiedRequester.unipost(
|
||||||
buildStandardUrl(baseUrl, createRouting),
|
buildStandardUrl(baseUrl, createRouting),
|
||||||
BodyPair(listInputSerializer, values),
|
BodyPair(listInputSerializer, values),
|
||||||
listObjectsSerializer
|
listObjectsSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun update(id: IdType, value: InputValue): ObjectType? = client.unipost(
|
override suspend fun update(id: IdType, value: InputValue): ObjectType? = unifiedRequester.unipost(
|
||||||
buildStandardUrl(baseUrl, updateRouting),
|
buildStandardUrl(baseUrl, updateRouting),
|
||||||
BodyPair(inputUpdateSerializer, id to value),
|
BodyPair(inputUpdateSerializer, id to value),
|
||||||
objectsNullableSerializer
|
objectsNullableSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValue>>): List<ObjectType> = client.unipost(
|
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValue>>): List<ObjectType> = unifiedRequester.unipost(
|
||||||
buildStandardUrl(baseUrl, updateManyRouting),
|
buildStandardUrl(baseUrl, updateManyRouting),
|
||||||
BodyPair(listInputUpdateSerializer, values),
|
BodyPair(listInputUpdateSerializer, values),
|
||||||
listObjectsSerializer
|
listObjectsSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun deleteById(ids: List<IdType>) = client.unipost(
|
override suspend fun deleteById(ids: List<IdType>) = unifiedRequester.unipost(
|
||||||
buildStandardUrl(baseUrl, deleteByIdRouting),
|
buildStandardUrl(baseUrl, deleteByIdRouting),
|
||||||
BodyPair(listIdsSerializer, ids),
|
BodyPair(listIdsSerializer, ids),
|
||||||
Unit.serializer()
|
Unit.serializer()
|
||||||
|
@@ -1,67 +1,90 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.key_value
|
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.*
|
||||||
import dev.inmo.micro_utils.ktor.client.uniget
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
|
||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
|
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.*
|
||||||
import kotlinx.serialization.builtins.serializer
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
|
||||||
class KtorReadStandardKeyValueRepo<Key, Value> (
|
class KtorReadStandardKeyValueRepo<Key, Value> (
|
||||||
private var baseUrl: String,
|
private val baseUrl: String,
|
||||||
private var client: HttpClient = HttpClient(),
|
private val unifiedRequester: UnifiedRequester,
|
||||||
private var keySerializer: KSerializer<Key>,
|
private val keySerializer: KSerializer<Key>,
|
||||||
private var valueSerializer: KSerializer<Value>,
|
private val valueSerializer: KSerializer<Value>,
|
||||||
private var valueNullableSerializer: KSerializer<Value?>,
|
private val valueNullableSerializer: KSerializer<Value?>
|
||||||
) : ReadStandardKeyValueRepo<Key, Value> {
|
) : ReadStandardKeyValueRepo<Key, Value> {
|
||||||
override suspend fun get(k: Key): Value? = client.uniget(
|
constructor(
|
||||||
|
baseUrl: String,
|
||||||
|
client: HttpClient,
|
||||||
|
keySerializer: KSerializer<Key>,
|
||||||
|
valueSerializer: KSerializer<Value>,
|
||||||
|
valueNullableSerializer: KSerializer<Value?>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
|
) : this (
|
||||||
|
baseUrl, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer, valueNullableSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun get(k: Key): Value? = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
getRoute,
|
getRoute,
|
||||||
mapOf(
|
mapOf(
|
||||||
keyParameterName to keySerializer.encodeUrlQueryValue(k)
|
keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, k)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
valueNullableSerializer
|
valueNullableSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> = client.uniget(
|
override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
valuesRoute,
|
valuesRoute,
|
||||||
mapOf(
|
mapOf(
|
||||||
reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed)
|
reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
|
||||||
) + pagination.asUrlQueryParts
|
) + pagination.asUrlQueryParts
|
||||||
),
|
),
|
||||||
PaginationResult.serializer(valueSerializer)
|
PaginationResult.serializer(valueSerializer)
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = client.uniget(
|
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
keysRoute,
|
keysRoute,
|
||||||
mapOf(
|
mapOf(
|
||||||
reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed)
|
reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
|
||||||
) + pagination.asUrlQueryParts
|
) + pagination.asUrlQueryParts
|
||||||
),
|
),
|
||||||
PaginationResult.serializer(keySerializer)
|
PaginationResult.serializer(keySerializer)
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun contains(key: Key): Boolean = client.uniget(
|
override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> = unifiedRequester.uniget(
|
||||||
|
buildStandardUrl(
|
||||||
|
baseUrl,
|
||||||
|
keysRoute,
|
||||||
|
mapOf(
|
||||||
|
valueParameterName to unifiedRequester.encodeUrlQueryValue(valueSerializer, v),
|
||||||
|
reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
|
||||||
|
) + pagination.asUrlQueryParts
|
||||||
|
),
|
||||||
|
PaginationResult.serializer(keySerializer)
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun contains(key: Key): Boolean = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
containsRoute,
|
containsRoute,
|
||||||
mapOf(
|
mapOf(
|
||||||
keyParameterName to keySerializer.encodeUrlQueryValue(key)
|
keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, key)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Boolean.serializer(),
|
Boolean.serializer(),
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun count(): Long = client.uniget(
|
override suspend fun count(): Long = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
countRoute,
|
countRoute,
|
||||||
|
@@ -1,27 +1,40 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.key_value
|
package dev.inmo.micro_utils.repos.ktor.client.key_value
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.client.UnifiedRequester
|
||||||
|
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
|
||||||
|
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
class KtorStandartKeyValueRepo<K, V> (
|
class KtorStandartKeyValueRepo<K, V> (
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
baseSubpart: String,
|
baseSubpart: String,
|
||||||
client: HttpClient = HttpClient(),
|
unifiedRequester: UnifiedRequester,
|
||||||
keySerializer: KSerializer<K>,
|
keySerializer: KSerializer<K>,
|
||||||
valueSerializer: KSerializer<V>,
|
valueSerializer: KSerializer<V>,
|
||||||
valueNullableSerializer: KSerializer<V?>
|
valueNullableSerializer: KSerializer<V?>
|
||||||
) : StandardKeyValueRepo<K, V>,
|
) : StandardKeyValueRepo<K, V>,
|
||||||
ReadStandardKeyValueRepo<K, V> by KtorReadStandardKeyValueRepo(
|
ReadStandardKeyValueRepo<K, V> by KtorReadStandardKeyValueRepo(
|
||||||
"$baseUrl/$baseSubpart",
|
"$baseUrl/$baseSubpart",
|
||||||
client,
|
unifiedRequester,
|
||||||
keySerializer,
|
keySerializer,
|
||||||
valueSerializer,
|
valueSerializer,
|
||||||
valueNullableSerializer
|
valueNullableSerializer
|
||||||
),
|
),
|
||||||
WriteStandardKeyValueRepo<K, V> by KtorWriteStandardKeyValueRepo(
|
WriteStandardKeyValueRepo<K, V> by KtorWriteStandardKeyValueRepo(
|
||||||
"$baseUrl/$baseSubpart",
|
"$baseUrl/$baseSubpart",
|
||||||
client,
|
unifiedRequester,
|
||||||
keySerializer,
|
keySerializer,
|
||||||
valueSerializer
|
valueSerializer
|
||||||
)
|
) {
|
||||||
|
constructor(
|
||||||
|
baseUrl: String,
|
||||||
|
baseSubpart: String,
|
||||||
|
client: HttpClient = HttpClient(),
|
||||||
|
keySerializer: KSerializer<K>,
|
||||||
|
valueSerializer: KSerializer<V>,
|
||||||
|
valueNullableSerializer: KSerializer<V?>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
|
) : this(baseUrl, baseSubpart, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer, valueNullableSerializer)
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.key_value
|
package dev.inmo.micro_utils.repos.ktor.client.key_value
|
||||||
|
|
||||||
import dev.inmo.micro_utils.ktor.client.*
|
import dev.inmo.micro_utils.ktor.client.*
|
||||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
|
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
@@ -11,23 +11,34 @@ import kotlinx.serialization.builtins.*
|
|||||||
|
|
||||||
class KtorWriteStandardKeyValueRepo<K, V> (
|
class KtorWriteStandardKeyValueRepo<K, V> (
|
||||||
private var baseUrl: String,
|
private var baseUrl: String,
|
||||||
private var client: HttpClient = HttpClient(),
|
private var unifiedRequester: UnifiedRequester,
|
||||||
private var keySerializer: KSerializer<K>,
|
private var keySerializer: KSerializer<K>,
|
||||||
private var valueSerializer: KSerializer<V>,
|
private var valueSerializer: KSerializer<V>,
|
||||||
) : WriteStandardKeyValueRepo<K, V> {
|
) : WriteStandardKeyValueRepo<K, V> {
|
||||||
private val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer)
|
private val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer)
|
||||||
private val keysListSerializer = ListSerializer(keySerializer)
|
private val keysListSerializer = ListSerializer(keySerializer)
|
||||||
override val onNewValue: Flow<Pair<K, V>> = client.createStandardWebsocketFlow(
|
|
||||||
|
constructor(
|
||||||
|
baseUrl: String,
|
||||||
|
client: HttpClient,
|
||||||
|
keySerializer: KSerializer<K>,
|
||||||
|
valueSerializer: KSerializer<V>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
|
) : this (
|
||||||
|
baseUrl, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
override val onNewValue: Flow<Pair<K, V>> = unifiedRequester.createStandardWebsocketFlow(
|
||||||
buildStandardUrl(baseUrl, onNewValueRoute),
|
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||||
deserializer = PairSerializer(keySerializer, valueSerializer)
|
deserializer = PairSerializer(keySerializer, valueSerializer)
|
||||||
)
|
)
|
||||||
|
|
||||||
override val onValueRemoved: Flow<K> = client.createStandardWebsocketFlow(
|
override val onValueRemoved: Flow<K> = unifiedRequester.createStandardWebsocketFlow(
|
||||||
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
||||||
deserializer = keySerializer
|
deserializer = keySerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun set(toSet: Map<K, V>) = client.unipost(
|
override suspend fun set(toSet: Map<K, V>) = unifiedRequester.unipost(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
setRoute
|
setRoute
|
||||||
@@ -36,7 +47,7 @@ class KtorWriteStandardKeyValueRepo<K, V> (
|
|||||||
Unit.serializer()
|
Unit.serializer()
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun unset(toUnset: List<K>) = client.unipost(
|
override suspend fun unset(toUnset: List<K>) = unifiedRequester.unipost(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
unsetRoute,
|
unsetRoute,
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.one_to_many
|
package dev.inmo.micro_utils.repos.ktor.client.one_to_many
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.client.UnifiedRequester
|
||||||
|
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
|
||||||
|
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
@@ -7,19 +10,28 @@ import kotlinx.serialization.KSerializer
|
|||||||
class KtorOneToManyKeyValueRepo<Key, Value>(
|
class KtorOneToManyKeyValueRepo<Key, Value>(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
baseSubpart: String,
|
baseSubpart: String,
|
||||||
client: HttpClient,
|
unifiedRequester: UnifiedRequester,
|
||||||
keySerializer: KSerializer<Key>,
|
keySerializer: KSerializer<Key>,
|
||||||
valueSerializer: KSerializer<Value>,
|
valueSerializer: KSerializer<Value>,
|
||||||
) : OneToManyKeyValueRepo<Key, Value>,
|
) : OneToManyKeyValueRepo<Key, Value>,
|
||||||
ReadOneToManyKeyValueRepo<Key, Value> by KtorReadOneToManyKeyValueRepo<Key, Value> (
|
ReadOneToManyKeyValueRepo<Key, Value> by KtorReadOneToManyKeyValueRepo<Key, Value> (
|
||||||
"$baseUrl/$baseSubpart",
|
"$baseUrl/$baseSubpart",
|
||||||
client,
|
unifiedRequester,
|
||||||
keySerializer,
|
keySerializer,
|
||||||
valueSerializer,
|
valueSerializer,
|
||||||
),
|
),
|
||||||
WriteOneToManyKeyValueRepo<Key, Value> by KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
WriteOneToManyKeyValueRepo<Key, Value> by KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
||||||
"$baseUrl/$baseSubpart",
|
"$baseUrl/$baseSubpart",
|
||||||
client,
|
unifiedRequester,
|
||||||
keySerializer,
|
keySerializer,
|
||||||
valueSerializer,
|
valueSerializer,
|
||||||
)
|
) {
|
||||||
|
constructor(
|
||||||
|
baseUrl: String,
|
||||||
|
baseSubpart: String,
|
||||||
|
client: HttpClient,
|
||||||
|
keySerializer: KSerializer<Key>,
|
||||||
|
valueSerializer: KSerializer<Value>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
|
) : this (baseUrl, baseSubpart, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer)
|
||||||
|
}
|
@@ -1,80 +1,102 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.one_to_many
|
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.*
|
||||||
import dev.inmo.micro_utils.ktor.client.uniget
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
|
||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
|
import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
|
||||||
|
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.one_to_many.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.builtins.serializer
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
|
||||||
class KtorReadOneToManyKeyValueRepo<Key, Value> (
|
class KtorReadOneToManyKeyValueRepo<Key, Value> (
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val client: HttpClient = HttpClient(),
|
private val unifiedRequester: UnifiedRequester,
|
||||||
private val keySerializer: KSerializer<Key>,
|
private val keySerializer: KSerializer<Key>,
|
||||||
private val valueSerializer: KSerializer<Value>,
|
private val valueSerializer: KSerializer<Value>
|
||||||
) : ReadOneToManyKeyValueRepo<Key, Value> {
|
) : ReadOneToManyKeyValueRepo<Key, Value> {
|
||||||
private val paginationValueResultSerializer = PaginationResult.serializer(valueSerializer)
|
private val paginationValueResultSerializer = PaginationResult.serializer(valueSerializer)
|
||||||
private val paginationKeyResultSerializer = PaginationResult.serializer(keySerializer)
|
private val paginationKeyResultSerializer = PaginationResult.serializer(keySerializer)
|
||||||
|
|
||||||
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> = client.uniget(
|
constructor(
|
||||||
|
baseUrl: String,
|
||||||
|
client: HttpClient,
|
||||||
|
keySerializer: KSerializer<Key>,
|
||||||
|
valueSerializer: KSerializer<Value>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
|
) : this (baseUrl, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer)
|
||||||
|
|
||||||
|
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
getRoute,
|
getRoute,
|
||||||
mapOf(
|
mapOf(
|
||||||
keyParameterName to keySerializer.encodeUrlQueryValue(k),
|
keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, k),
|
||||||
reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed)
|
reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
|
||||||
) + pagination.asUrlQueryParts
|
) + pagination.asUrlQueryParts
|
||||||
),
|
),
|
||||||
paginationValueResultSerializer
|
paginationValueResultSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = client.uniget(
|
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
keysRoute,
|
keysRoute,
|
||||||
mapOf(
|
mapOf(
|
||||||
reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed)
|
reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
|
||||||
) + pagination.asUrlQueryParts
|
) + pagination.asUrlQueryParts
|
||||||
),
|
),
|
||||||
paginationKeyResultSerializer
|
paginationKeyResultSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun contains(k: Key): Boolean = client.uniget(
|
override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> = unifiedRequester.uniget(
|
||||||
|
buildStandardUrl(
|
||||||
|
baseUrl,
|
||||||
|
keysRoute,
|
||||||
|
mapOf(
|
||||||
|
valueParameterName to unifiedRequester.encodeUrlQueryValue(valueSerializer, v),
|
||||||
|
reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
|
||||||
|
) + pagination.asUrlQueryParts
|
||||||
|
),
|
||||||
|
paginationKeyResultSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun contains(k: Key): Boolean = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
containsByKeyRoute,
|
containsByKeyRoute,
|
||||||
mapOf(keyParameterName to keySerializer.encodeUrlQueryValue(k))
|
mapOf(keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, k))
|
||||||
),
|
),
|
||||||
Boolean.serializer()
|
Boolean.serializer()
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun contains(k: Key, v: Value): Boolean = client.uniget(
|
override suspend fun contains(k: Key, v: Value): Boolean = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
containsByKeyValueRoute,
|
containsByKeyValueRoute,
|
||||||
mapOf(
|
mapOf(
|
||||||
keyParameterName to keySerializer.encodeUrlQueryValue(k),
|
keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, k),
|
||||||
valueParameterName to valueSerializer.encodeUrlQueryValue(v),
|
valueParameterName to unifiedRequester.encodeUrlQueryValue(valueSerializer, v),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
Boolean.serializer()
|
Boolean.serializer()
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun count(k: Key): Long = client.uniget(
|
override suspend fun count(k: Key): Long = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
countByKeyRoute,
|
countByKeyRoute,
|
||||||
mapOf(
|
mapOf(
|
||||||
keyParameterName to keySerializer.encodeUrlQueryValue(k)
|
keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, k)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
Long.serializer()
|
Long.serializer()
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun count(): Long = client.uniget(
|
override suspend fun count(): Long = unifiedRequester.uniget(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
countRoute,
|
countRoute,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.client.one_to_many
|
package dev.inmo.micro_utils.repos.ktor.client.one_to_many
|
||||||
|
|
||||||
import dev.inmo.micro_utils.ktor.client.*
|
import dev.inmo.micro_utils.ktor.client.*
|
||||||
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
|
import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
|
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
@@ -11,26 +11,37 @@ import kotlinx.serialization.builtins.*
|
|||||||
|
|
||||||
class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val client: HttpClient = HttpClient(),
|
private val unifiedRequester: UnifiedRequester,
|
||||||
private val keySerializer: KSerializer<Key>,
|
private val keySerializer: KSerializer<Key>,
|
||||||
private val valueSerializer: KSerializer<Value>
|
private val valueSerializer: KSerializer<Value>
|
||||||
) : WriteOneToManyKeyValueRepo<Key, Value> {
|
) : WriteOneToManyKeyValueRepo<Key, Value> {
|
||||||
private val keyValueSerializer = PairSerializer(keySerializer, valueSerializer)
|
private val keyValueSerializer = PairSerializer(keySerializer, valueSerializer)
|
||||||
private val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer))
|
private val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer))
|
||||||
override val onNewValue: Flow<Pair<Key, Value>> = client.createStandardWebsocketFlow(
|
|
||||||
|
constructor(
|
||||||
|
baseUrl: String,
|
||||||
|
client: HttpClient,
|
||||||
|
keySerializer: KSerializer<Key>,
|
||||||
|
valueSerializer: KSerializer<Value>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
|
) : this (
|
||||||
|
baseUrl, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
override val onNewValue: Flow<Pair<Key, Value>> = unifiedRequester.createStandardWebsocketFlow(
|
||||||
buildStandardUrl(baseUrl, onNewValueRoute),
|
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||||
deserializer = keyValueSerializer
|
deserializer = keyValueSerializer
|
||||||
)
|
)
|
||||||
override val onValueRemoved: Flow<Pair<Key, Value>> = client.createStandardWebsocketFlow(
|
override val onValueRemoved: Flow<Pair<Key, Value>> = unifiedRequester.createStandardWebsocketFlow(
|
||||||
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
||||||
deserializer = keyValueSerializer
|
deserializer = keyValueSerializer
|
||||||
)
|
)
|
||||||
override val onDataCleared: Flow<Key> = client.createStandardWebsocketFlow(
|
override val onDataCleared: Flow<Key> = unifiedRequester.createStandardWebsocketFlow(
|
||||||
buildStandardUrl(baseUrl, onDataClearedRoute),
|
buildStandardUrl(baseUrl, onDataClearedRoute),
|
||||||
deserializer = keySerializer
|
deserializer = keySerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun remove(toRemove: Map<Key, List<Value>>) = client.unipost(
|
override suspend fun remove(toRemove: Map<Key, List<Value>>) = unifiedRequester.unipost(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
removeRoute,
|
removeRoute,
|
||||||
@@ -39,15 +50,15 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
|||||||
Unit.serializer(),
|
Unit.serializer(),
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun add(toAdd: Map<Key, List<Value>>) = client.unipost(
|
override suspend fun add(toAdd: Map<Key, List<Value>>) = unifiedRequester.unipost(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
clearRoute,
|
addRoute,
|
||||||
),
|
),
|
||||||
BodyPair(keyValueMapSerializer, toAdd),
|
BodyPair(keyValueMapSerializer, toAdd),
|
||||||
Unit.serializer(),
|
Unit.serializer(),
|
||||||
)
|
)
|
||||||
override suspend fun clear(k: Key) = client.unipost(
|
override suspend fun clear(k: Key) = unifiedRequester.unipost(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
clearRoute,
|
clearRoute,
|
||||||
@@ -55,4 +66,13 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
|||||||
BodyPair(keySerializer, k),
|
BodyPair(keySerializer, k),
|
||||||
Unit.serializer(),
|
Unit.serializer(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override suspend fun set(toSet: Map<Key, List<Value>>) = unifiedRequester.unipost(
|
||||||
|
buildStandardUrl(
|
||||||
|
baseUrl,
|
||||||
|
setRoute,
|
||||||
|
),
|
||||||
|
BodyPair(keyValueMapSerializer, toSet),
|
||||||
|
Unit.serializer(),
|
||||||
|
)
|
||||||
}
|
}
|
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
id "kotlin-android-extensions"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
@@ -0,0 +1,5 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.common
|
||||||
|
|
||||||
|
const val keyParameterName = "key"
|
||||||
|
const val valueParameterName = "value"
|
||||||
|
const val reversedParameterName = "reversed"
|
@@ -1,5 +1,8 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.common.one_to_many
|
package dev.inmo.micro_utils.repos.ktor.common.one_to_many
|
||||||
|
|
||||||
const val keyParameterName = "key"
|
@Deprecated("Replaced", ReplaceWith("keyParameterName", "dev.inmo.micro_utils.repos.ktor.common.keyParameterName"))
|
||||||
const val valueParameterName = "value"
|
const val keyParameterName = dev.inmo.micro_utils.repos.ktor.common.keyParameterName
|
||||||
const val reversedParameterName = "reversed"
|
@Deprecated("Replaced", ReplaceWith("valueParameterName", "dev.inmo.micro_utils.repos.ktor.common.valueParameterName"))
|
||||||
|
const val valueParameterName = dev.inmo.micro_utils.repos.ktor.common.valueParameterName
|
||||||
|
@Deprecated("Replaced", ReplaceWith("reversedParameterName", "dev.inmo.micro_utils.repos.ktor.common.reversedParameterName"))
|
||||||
|
const val reversedParameterName = dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
|
@@ -13,4 +13,5 @@ const val onDataClearedRoute = "onDataCleared"
|
|||||||
|
|
||||||
const val addRoute = "add"
|
const val addRoute = "add"
|
||||||
const val removeRoute = "remove"
|
const val removeRoute = "remove"
|
||||||
const val clearRoute = "clear"
|
const val clearRoute = "clear"
|
||||||
|
const val setRoute = "set"
|
@@ -1,12 +1,14 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.server.crud
|
package dev.inmo.micro_utils.repos.ktor.server.crud
|
||||||
|
|
||||||
import dev.inmo.micro_utils.ktor.server.decodeUrlQueryValueOrSendError
|
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
|
||||||
import dev.inmo.micro_utils.ktor.server.unianswer
|
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.PaginationResult
|
||||||
import dev.inmo.micro_utils.pagination.extractPagination
|
import dev.inmo.micro_utils.pagination.extractPagination
|
||||||
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.routing.get
|
import io.ktor.routing.get
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
@@ -16,47 +18,65 @@ fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes(
|
|||||||
originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>,
|
originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>,
|
||||||
objectsSerializer: KSerializer<ObjectType>,
|
objectsSerializer: KSerializer<ObjectType>,
|
||||||
objectsNullableSerializer: KSerializer<ObjectType?>,
|
objectsNullableSerializer: KSerializer<ObjectType?>,
|
||||||
idsSerializer: KSerializer<IdType>
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
unifiedRouter: UnifiedRouter
|
||||||
) {
|
) {
|
||||||
val paginationResultSerializer = PaginationResult.serializer(objectsSerializer)
|
val paginationResultSerializer = PaginationResult.serializer(objectsSerializer)
|
||||||
|
|
||||||
get(getByPaginationRouting) {
|
get(getByPaginationRouting) {
|
||||||
val pagination = call.request.queryParameters.extractPagination
|
unifiedRouter.apply {
|
||||||
|
val pagination = call.request.queryParameters.extractPagination
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
paginationResultSerializer,
|
paginationResultSerializer,
|
||||||
originalRepo.getByPagination(pagination)
|
originalRepo.getByPagination(pagination)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(getByIdRouting) {
|
get(getByIdRouting) {
|
||||||
val id = call.decodeUrlQueryValueOrSendError(
|
unifiedRouter.apply {
|
||||||
"id",
|
val id = decodeUrlQueryValueOrSendError(
|
||||||
idsSerializer
|
"id",
|
||||||
) ?: return@get
|
idsSerializer
|
||||||
|
) ?: return@get
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
objectsNullableSerializer,
|
objectsNullableSerializer,
|
||||||
originalRepo.getById(id)
|
originalRepo.getById(id)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(containsRouting) {
|
get(containsRouting) {
|
||||||
val id = call.decodeUrlQueryValueOrSendError(
|
unifiedRouter.apply {
|
||||||
"id",
|
val id = decodeUrlQueryValueOrSendError(
|
||||||
idsSerializer
|
"id",
|
||||||
) ?: return@get
|
idsSerializer
|
||||||
|
) ?: return@get
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
Boolean.serializer(),
|
Boolean.serializer(),
|
||||||
originalRepo.contains(id)
|
originalRepo.contains(id)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(countRouting) {
|
get(countRouting) {
|
||||||
call.unianswer(
|
unifiedRouter.apply {
|
||||||
Long.serializer(),
|
unianswer(
|
||||||
originalRepo.count()
|
Long.serializer(),
|
||||||
)
|
originalRepo.count()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes(
|
||||||
|
originalRepo: ReadStandardCRUDRepo<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))
|
||||||
|
@@ -1,6 +1,11 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.server.crud
|
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.UnifiedRouter
|
||||||
|
import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType
|
||||||
import dev.inmo.micro_utils.repos.StandardCRUDRepo
|
import dev.inmo.micro_utils.repos.StandardCRUDRepo
|
||||||
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.routing.route
|
import io.ktor.routing.route
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
@@ -11,10 +16,24 @@ fun <ObjectType, IdType, InputValue> Route.configureStandardCrudRepoRoutes(
|
|||||||
objectsSerializer: KSerializer<ObjectType>,
|
objectsSerializer: KSerializer<ObjectType>,
|
||||||
objectsNullableSerializer: KSerializer<ObjectType?>,
|
objectsNullableSerializer: KSerializer<ObjectType?>,
|
||||||
inputsSerializer: KSerializer<InputValue>,
|
inputsSerializer: KSerializer<InputValue>,
|
||||||
idsSerializer: KSerializer<IdType>
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
unifiedRouter: UnifiedRouter
|
||||||
) {
|
) {
|
||||||
route(baseSubpart) {
|
route(baseSubpart) {
|
||||||
configureReadStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer)
|
configureReadStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer, unifiedRouter)
|
||||||
configureWriteStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer)
|
configureWriteStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, unifiedRouter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <ObjectType, IdType, InputValue> Route.configureStandardCrudRepoRoutes(
|
||||||
|
baseSubpart: String,
|
||||||
|
originalRepo: StandardCRUDRepo<ObjectType, IdType, InputValue>,
|
||||||
|
objectsSerializer: KSerializer<ObjectType>,
|
||||||
|
objectsNullableSerializer: KSerializer<ObjectType?>,
|
||||||
|
inputsSerializer: KSerializer<InputValue>,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
|
||||||
|
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
|
||||||
|
) = configureStandardCrudRepoRoutes(
|
||||||
|
baseSubpart, originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType)
|
||||||
|
)
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.server.crud
|
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.ktor.server.*
|
||||||
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
|
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.routing.post
|
import io.ktor.routing.post
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
@@ -14,7 +17,8 @@ fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes(
|
|||||||
objectsSerializer: KSerializer<ObjectType>,
|
objectsSerializer: KSerializer<ObjectType>,
|
||||||
objectsNullableSerializer: KSerializer<ObjectType?>,
|
objectsNullableSerializer: KSerializer<ObjectType?>,
|
||||||
inputsSerializer: KSerializer<InputValue>,
|
inputsSerializer: KSerializer<InputValue>,
|
||||||
idsSerializer: KSerializer<IdType>
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
unifiedRouter: UnifiedRouter
|
||||||
) {
|
) {
|
||||||
val listObjectsSerializer = ListSerializer(objectsSerializer)
|
val listObjectsSerializer = ListSerializer(objectsSerializer)
|
||||||
val listInputSerializer = ListSerializer(inputsSerializer)
|
val listInputSerializer = ListSerializer(inputsSerializer)
|
||||||
@@ -25,58 +29,80 @@ fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes(
|
|||||||
)
|
)
|
||||||
val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer)
|
val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer)
|
||||||
|
|
||||||
includeWebsocketHandling(
|
unifiedRouter.apply {
|
||||||
newObjectsFlowRouting,
|
includeWebsocketHandling(
|
||||||
originalRepo.newObjectsFlow,
|
newObjectsFlowRouting,
|
||||||
objectsSerializer
|
originalRepo.newObjectsFlow,
|
||||||
)
|
objectsSerializer
|
||||||
includeWebsocketHandling(
|
)
|
||||||
updatedObjectsFlowRouting,
|
includeWebsocketHandling(
|
||||||
originalRepo.updatedObjectsFlow,
|
updatedObjectsFlowRouting,
|
||||||
objectsSerializer
|
originalRepo.updatedObjectsFlow,
|
||||||
)
|
objectsSerializer
|
||||||
includeWebsocketHandling(
|
)
|
||||||
deletedObjectsIdsFlowRouting,
|
includeWebsocketHandling(
|
||||||
originalRepo.deletedObjectsIdsFlow,
|
deletedObjectsIdsFlowRouting,
|
||||||
idsSerializer
|
originalRepo.deletedObjectsIdsFlow,
|
||||||
)
|
idsSerializer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
post(createRouting) {
|
post(createRouting) {
|
||||||
call.unianswer(
|
unifiedRouter.apply {
|
||||||
listObjectsSerializer,
|
unianswer(
|
||||||
originalRepo.create(
|
listObjectsSerializer,
|
||||||
call.uniload(listInputSerializer)
|
originalRepo.create(
|
||||||
|
uniload(listInputSerializer)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post(updateRouting) {
|
post(updateRouting) {
|
||||||
val (id, input) = call.uniload(inputUpdateSerializer)
|
unifiedRouter.apply {
|
||||||
call.unianswer(
|
val (id, input) = uniload(inputUpdateSerializer)
|
||||||
objectsNullableSerializer,
|
unianswer(
|
||||||
originalRepo.update(
|
objectsNullableSerializer,
|
||||||
id, input
|
originalRepo.update(
|
||||||
|
id, input
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post(updateManyRouting) {
|
post(updateManyRouting) {
|
||||||
val updates = call.uniload(listInputUpdateSerializer)
|
unifiedRouter.apply {
|
||||||
call.unianswer(
|
val updates = uniload(listInputUpdateSerializer)
|
||||||
listObjectsSerializer,
|
unianswer(
|
||||||
originalRepo.update(
|
listObjectsSerializer,
|
||||||
updates
|
originalRepo.update(
|
||||||
|
updates
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post(deleteByIdRouting) {
|
post(deleteByIdRouting) {
|
||||||
val ids = call.uniload(listIdsSerializer)
|
unifiedRouter.apply {
|
||||||
call.unianswer(
|
val ids = uniload(listIdsSerializer)
|
||||||
Unit.serializer(),
|
unianswer(
|
||||||
originalRepo.deleteById(
|
Unit.serializer(),
|
||||||
ids
|
originalRepo.deleteById(
|
||||||
|
ids
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes(
|
||||||
|
originalRepo: WriteStandardCRUDRepo<ObjectType, IdType, InputValue>,
|
||||||
|
objectsSerializer: KSerializer<ObjectType>,
|
||||||
|
objectsNullableSerializer: KSerializer<ObjectType?>,
|
||||||
|
inputsSerializer: KSerializer<InputValue>,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
|
||||||
|
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
|
||||||
|
) = configureWriteStandardCrudRepoRoutes(
|
||||||
|
originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType)
|
||||||
|
)
|
||||||
|
@@ -1,16 +1,22 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.server.key_value
|
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.UnifiedRouter
|
||||||
|
import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType
|
||||||
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
|
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
|
||||||
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.routing.route
|
import io.ktor.routing.route
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
|
|
||||||
fun <K, V> Route.configureStandartKeyValueRepoRoutes(
|
fun <K, V> Route.configureStandardKeyValueRepoRoutes(
|
||||||
baseSubpart: String,
|
baseSubpart: String,
|
||||||
originalRepo: StandardKeyValueRepo<K, V>,
|
originalRepo: StandardKeyValueRepo<K, V>,
|
||||||
keySerializer: KSerializer<K>,
|
keySerializer: KSerializer<K>,
|
||||||
valueSerializer: KSerializer<V>,
|
valueSerializer: KSerializer<V>,
|
||||||
valueNullableSerializer: KSerializer<V?>,
|
valueNullableSerializer: KSerializer<V?>,
|
||||||
|
unifiedRouter: UnifiedRouter
|
||||||
) {
|
) {
|
||||||
route(baseSubpart) {
|
route(baseSubpart) {
|
||||||
configureReadStandartKeyValueRepoRoutes(
|
configureReadStandartKeyValueRepoRoutes(
|
||||||
@@ -18,11 +24,23 @@ fun <K, V> Route.configureStandartKeyValueRepoRoutes(
|
|||||||
keySerializer,
|
keySerializer,
|
||||||
valueSerializer,
|
valueSerializer,
|
||||||
valueNullableSerializer,
|
valueNullableSerializer,
|
||||||
|
unifiedRouter
|
||||||
)
|
)
|
||||||
configureWriteStandartKeyValueRepoRoutes(
|
configureWriteStandardKeyValueRepoRoutes(
|
||||||
originalRepo,
|
originalRepo,
|
||||||
keySerializer,
|
keySerializer,
|
||||||
valueSerializer,
|
valueSerializer,
|
||||||
|
unifiedRouter
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <K, V> Route.configureStandartKeyValueRepoRoutes(
|
||||||
|
baseSubpart: String,
|
||||||
|
originalRepo: StandardKeyValueRepo<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))
|
@@ -1,12 +1,15 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.server.key_value
|
package dev.inmo.micro_utils.repos.ktor.server.key_value
|
||||||
|
|
||||||
import dev.inmo.micro_utils.ktor.server.decodeUrlQueryValueOrSendError
|
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
|
||||||
import dev.inmo.micro_utils.ktor.server.unianswer
|
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.PaginationResult
|
||||||
import dev.inmo.micro_utils.pagination.extractPagination
|
import dev.inmo.micro_utils.pagination.extractPagination
|
||||||
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
|
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.routing.get
|
import io.ktor.routing.get
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
@@ -17,61 +20,84 @@ fun <K, V> Route.configureReadStandartKeyValueRepoRoutes (
|
|||||||
keySerializer: KSerializer<K>,
|
keySerializer: KSerializer<K>,
|
||||||
valueSerializer: KSerializer<V>,
|
valueSerializer: KSerializer<V>,
|
||||||
valueNullableSerializer: KSerializer<V?>,
|
valueNullableSerializer: KSerializer<V?>,
|
||||||
|
unifiedRouter: UnifiedRouter
|
||||||
) {
|
) {
|
||||||
get(getRoute) {
|
get(getRoute) {
|
||||||
val key = call.decodeUrlQueryValueOrSendError(
|
unifiedRouter.apply {
|
||||||
keyParameterName,
|
val key = decodeUrlQueryValueOrSendError(
|
||||||
keySerializer
|
keyParameterName,
|
||||||
) ?: return@get
|
keySerializer
|
||||||
|
) ?: return@get
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
valueNullableSerializer,
|
valueNullableSerializer,
|
||||||
originalRepo.get(key)
|
originalRepo.get(key)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(valuesRoute) {
|
get(valuesRoute) {
|
||||||
val parination = call.request.queryParameters.extractPagination;
|
unifiedRouter.apply {
|
||||||
val reversed = call.decodeUrlQueryValueOrSendError(
|
val parination = call.request.queryParameters.extractPagination;
|
||||||
reversedParameterName,
|
val reversed = decodeUrlQueryValueOrSendError(
|
||||||
Boolean.serializer()
|
reversedParameterName,
|
||||||
) ?: return@get
|
Boolean.serializer()
|
||||||
|
) ?: return@get
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
PaginationResult.serializer(valueSerializer),
|
PaginationResult.serializer(valueSerializer),
|
||||||
originalRepo.values(parination, reversed)
|
originalRepo.values(parination, reversed)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(keysRoute) {
|
get(keysRoute) {
|
||||||
val parination = call.request.queryParameters.extractPagination;
|
unifiedRouter.apply {
|
||||||
val reversed = call.decodeUrlQueryValueOrSendError(
|
val parination = call.request.queryParameters.extractPagination;
|
||||||
reversedParameterName,
|
val reversed = decodeUrlQueryValueOrSendError(
|
||||||
Boolean.serializer()
|
reversedParameterName,
|
||||||
) ?: return@get
|
Boolean.serializer()
|
||||||
|
) ?: return@get
|
||||||
|
val value = decodeUrlQueryValue(valueParameterName, valueSerializer)
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
PaginationResult.serializer(keySerializer),
|
PaginationResult.serializer(keySerializer),
|
||||||
originalRepo.keys(parination, reversed)
|
value?.let { originalRepo.keys(value, parination, reversed) } ?: originalRepo.keys(parination, reversed)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(containsRoute) {
|
get(containsRoute) {
|
||||||
val key = call.decodeUrlQueryValueOrSendError(
|
unifiedRouter.apply {
|
||||||
keyParameterName,
|
val key = decodeUrlQueryValueOrSendError(
|
||||||
keySerializer
|
keyParameterName,
|
||||||
) ?: return@get
|
keySerializer
|
||||||
|
) ?: return@get
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
Boolean.serializer(),
|
Boolean.serializer(),
|
||||||
originalRepo.contains(key)
|
originalRepo.contains(key)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(countRoute) {
|
get(countRoute) {
|
||||||
call.unianswer(
|
unifiedRouter.apply {
|
||||||
Long.serializer(),
|
unianswer(
|
||||||
originalRepo.count()
|
Long.serializer(),
|
||||||
)
|
originalRepo.count()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <K, V> Route.configureReadStandartKeyValueRepoRoutes (
|
||||||
|
originalRepo: ReadStandardKeyValueRepo<K, V>,
|
||||||
|
keySerializer: KSerializer<K>,
|
||||||
|
valueSerializer: KSerializer<V>,
|
||||||
|
valueNullableSerializer: KSerializer<V?>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
|
||||||
|
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
|
||||||
|
) = configureReadStandartKeyValueRepoRoutes(
|
||||||
|
originalRepo, keySerializer, valueSerializer, valueNullableSerializer, UnifiedRouter(serialFormat, serialFormatContentType)
|
||||||
|
)
|
||||||
|
@@ -1,44 +1,61 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.server.key_value
|
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.ktor.server.*
|
||||||
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
|
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
||||||
import io.ktor.application.call
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.routing.post
|
import io.ktor.routing.post
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.builtins.*
|
import kotlinx.serialization.builtins.*
|
||||||
|
|
||||||
|
fun <K, V> Route.configureWriteStandardKeyValueRepoRoutes (
|
||||||
|
originalRepo: WriteStandardKeyValueRepo<K, V>,
|
||||||
|
keySerializer: KSerializer<K>,
|
||||||
|
valueSerializer: KSerializer<V>,
|
||||||
|
unifiedRouter: UnifiedRouter
|
||||||
|
) {
|
||||||
|
val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer)
|
||||||
|
val keysListSerializer = ListSerializer(keySerializer)
|
||||||
|
unifiedRouter.apply {
|
||||||
|
includeWebsocketHandling(
|
||||||
|
onNewValueRoute,
|
||||||
|
originalRepo.onNewValue,
|
||||||
|
PairSerializer(keySerializer, valueSerializer)
|
||||||
|
)
|
||||||
|
|
||||||
|
includeWebsocketHandling(
|
||||||
|
onValueRemovedRoute,
|
||||||
|
originalRepo.onValueRemoved,
|
||||||
|
keySerializer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
post(setRoute) {
|
||||||
|
unifiedRouter.apply {
|
||||||
|
val toSet = uniload(
|
||||||
|
keyValueMapSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
unianswer(Unit.serializer(), originalRepo.set(toSet))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post(unsetRoute) {
|
||||||
|
unifiedRouter.apply {
|
||||||
|
val toUnset = uniload(keysListSerializer)
|
||||||
|
|
||||||
|
unianswer(Unit.serializer(), originalRepo.unset(toUnset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun <K, V> Route.configureWriteStandartKeyValueRepoRoutes (
|
fun <K, V> Route.configureWriteStandartKeyValueRepoRoutes (
|
||||||
originalRepo: WriteStandardKeyValueRepo<K, V>,
|
originalRepo: WriteStandardKeyValueRepo<K, V>,
|
||||||
keySerializer: KSerializer<K>,
|
keySerializer: KSerializer<K>,
|
||||||
valueSerializer: KSerializer<V>,
|
valueSerializer: KSerializer<V>,
|
||||||
) {
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
|
||||||
val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer)
|
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
|
||||||
val keysListSerializer = ListSerializer(keySerializer)
|
) = configureWriteStandardKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType))
|
||||||
includeWebsocketHandling(
|
|
||||||
onNewValueRoute,
|
|
||||||
originalRepo.onNewValue,
|
|
||||||
PairSerializer(keySerializer, valueSerializer)
|
|
||||||
)
|
|
||||||
|
|
||||||
includeWebsocketHandling(
|
|
||||||
onValueRemovedRoute,
|
|
||||||
originalRepo.onValueRemoved,
|
|
||||||
keySerializer
|
|
||||||
)
|
|
||||||
|
|
||||||
post(setRoute) {
|
|
||||||
val toSet = call.uniload(
|
|
||||||
keyValueMapSerializer
|
|
||||||
)
|
|
||||||
|
|
||||||
call.unianswer(Unit.serializer(), originalRepo.set(toSet))
|
|
||||||
}
|
|
||||||
|
|
||||||
post(unsetRoute) {
|
|
||||||
val toUnset = call.uniload(keysListSerializer)
|
|
||||||
|
|
||||||
call.unianswer(Unit.serializer(), originalRepo.unset(toUnset))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,6 +1,11 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.server.one_to_many
|
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.UnifiedRouter
|
||||||
|
import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType
|
||||||
import dev.inmo.micro_utils.repos.OneToManyKeyValueRepo
|
import dev.inmo.micro_utils.repos.OneToManyKeyValueRepo
|
||||||
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.routing.route
|
import io.ktor.routing.route
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
@@ -9,10 +14,22 @@ fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes(
|
|||||||
baseSubpart: String,
|
baseSubpart: String,
|
||||||
originalRepo: OneToManyKeyValueRepo<Key, Value>,
|
originalRepo: OneToManyKeyValueRepo<Key, Value>,
|
||||||
keySerializer: KSerializer<Key>,
|
keySerializer: KSerializer<Key>,
|
||||||
valueSealizer: KSerializer<Value>,
|
valueSerializer: KSerializer<Value>,
|
||||||
|
unifiedRouter: UnifiedRouter
|
||||||
) {
|
) {
|
||||||
route(baseSubpart) {
|
route(baseSubpart) {
|
||||||
configureOneToManyReadKeyValueRepoRoutes(originalRepo, keySerializer, valueSealizer)
|
configureOneToManyReadKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, unifiedRouter)
|
||||||
configureOneToManyWriteKeyValueRepoRoutes(originalRepo, keySerializer, valueSealizer)
|
configureOneToManyWriteKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, unifiedRouter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes(
|
||||||
|
baseSubpart: String,
|
||||||
|
originalRepo: OneToManyKeyValueRepo<Key, Value>,
|
||||||
|
keySerializer: KSerializer<Key>,
|
||||||
|
valueSerializer: KSerializer<Value>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
|
||||||
|
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
|
||||||
|
) = configureOneToManyKeyValueRepoRoutes(
|
||||||
|
baseSubpart, originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType)
|
||||||
|
)
|
@@ -1,11 +1,18 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.server.one_to_many
|
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.ktor.server.*
|
||||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||||
import dev.inmo.micro_utils.pagination.extractPagination
|
import dev.inmo.micro_utils.pagination.extractPagination
|
||||||
import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
|
import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.*
|
||||||
|
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.one_to_many.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.routing.get
|
import io.ktor.routing.get
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
@@ -14,85 +21,110 @@ import kotlinx.serialization.builtins.serializer
|
|||||||
fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
|
fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
|
||||||
originalRepo: ReadOneToManyKeyValueRepo<Key, Value>,
|
originalRepo: ReadOneToManyKeyValueRepo<Key, Value>,
|
||||||
keySerializer: KSerializer<Key>,
|
keySerializer: KSerializer<Key>,
|
||||||
valueSealizer: KSerializer<Value>,
|
valueSerializer: KSerializer<Value>,
|
||||||
|
unifiedRouter: UnifiedRouter
|
||||||
) {
|
) {
|
||||||
val paginationKeyResult = PaginationResult.serializer(keySerializer)
|
val paginationKeyResult = PaginationResult.serializer(keySerializer)
|
||||||
val paginationValueResult = PaginationResult.serializer(valueSealizer)
|
val paginationValueResult = PaginationResult.serializer(valueSerializer)
|
||||||
|
|
||||||
get(getRoute) {
|
get(getRoute) {
|
||||||
val pagination = call.request.queryParameters.extractPagination
|
unifiedRouter.apply {
|
||||||
val key = call.decodeUrlQueryValueOrSendError(
|
val pagination = call.request.queryParameters.extractPagination
|
||||||
keyParameterName,
|
val key = decodeUrlQueryValueOrSendError(
|
||||||
keySerializer
|
keyParameterName,
|
||||||
) ?: return@get
|
keySerializer
|
||||||
val reversed = call.decodeUrlQueryValue(
|
) ?: return@get
|
||||||
reversedParameterName,
|
val reversed = decodeUrlQueryValue(
|
||||||
Boolean.serializer()
|
reversedParameterName,
|
||||||
) ?: false
|
Boolean.serializer()
|
||||||
|
) ?: false
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
paginationValueResult,
|
paginationValueResult,
|
||||||
originalRepo.get(key, pagination, reversed)
|
originalRepo.get(key, pagination, reversed)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(keysRoute) {
|
get(keysRoute) {
|
||||||
val pagination = call.request.queryParameters.extractPagination
|
unifiedRouter.apply {
|
||||||
val reversed = call.decodeUrlQueryValue(
|
val pagination = call.request.queryParameters.extractPagination
|
||||||
reversedParameterName,
|
val reversed = decodeUrlQueryValue(
|
||||||
Boolean.serializer()
|
reversedParameterName,
|
||||||
) ?: false
|
Boolean.serializer()
|
||||||
|
) ?: false
|
||||||
|
val value: Value? = decodeUrlQueryValue(
|
||||||
|
valueParameterName,
|
||||||
|
valueSerializer
|
||||||
|
)
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
paginationKeyResult,
|
paginationKeyResult,
|
||||||
originalRepo.keys(pagination, reversed)
|
value?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(containsByKeyRoute) {
|
get(containsByKeyRoute) {
|
||||||
val key = call.decodeUrlQueryValueOrSendError(
|
unifiedRouter.apply {
|
||||||
keyParameterName,
|
val key = decodeUrlQueryValueOrSendError(
|
||||||
keySerializer
|
keyParameterName,
|
||||||
) ?: return@get
|
keySerializer
|
||||||
|
) ?: return@get
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
Boolean.serializer(),
|
Boolean.serializer(),
|
||||||
originalRepo.contains(key)
|
originalRepo.contains(key)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(containsByKeyValueRoute) {
|
get(containsByKeyValueRoute) {
|
||||||
val key = call.decodeUrlQueryValueOrSendError(
|
unifiedRouter.apply {
|
||||||
keyParameterName,
|
val key = decodeUrlQueryValueOrSendError(
|
||||||
keySerializer
|
keyParameterName,
|
||||||
) ?: return@get
|
keySerializer
|
||||||
val value = call.decodeUrlQueryValueOrSendError(
|
) ?: return@get
|
||||||
valueParameterName,
|
val value = decodeUrlQueryValueOrSendError(
|
||||||
valueSealizer
|
valueParameterName,
|
||||||
) ?: return@get
|
valueSerializer
|
||||||
|
) ?: return@get
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
Boolean.serializer(),
|
Boolean.serializer(),
|
||||||
originalRepo.contains(key, value)
|
originalRepo.contains(key, value)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(countByKeyRoute) {
|
get(countByKeyRoute) {
|
||||||
val key = call.decodeUrlQueryValueOrSendError(
|
unifiedRouter.apply {
|
||||||
keyParameterName,
|
val key = decodeUrlQueryValueOrSendError(
|
||||||
keySerializer
|
keyParameterName,
|
||||||
) ?: return@get
|
keySerializer
|
||||||
|
) ?: return@get
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
Long.serializer(),
|
Long.serializer(),
|
||||||
originalRepo.count(key)
|
originalRepo.count(key)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(countRoute) {
|
get(countRoute) {
|
||||||
call.unianswer(
|
unifiedRouter.apply {
|
||||||
Long.serializer(),
|
unianswer(
|
||||||
originalRepo.count()
|
Long.serializer(),
|
||||||
)
|
originalRepo.count()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
|
||||||
|
originalRepo: ReadOneToManyKeyValueRepo<Key, Value>,
|
||||||
|
keySerializer: KSerializer<Key>,
|
||||||
|
valueSerializer: KSerializer<Value>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
|
||||||
|
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
|
||||||
|
) = configureOneToManyReadKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType))
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.server.one_to_many
|
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.ktor.server.*
|
||||||
import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
|
import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
|
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.routing.post
|
import io.ktor.routing.post
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
@@ -13,52 +16,78 @@ fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes(
|
|||||||
originalRepo: WriteOneToManyKeyValueRepo<Key, Value>,
|
originalRepo: WriteOneToManyKeyValueRepo<Key, Value>,
|
||||||
keySerializer: KSerializer<Key>,
|
keySerializer: KSerializer<Key>,
|
||||||
valueSerializer: KSerializer<Value>,
|
valueSerializer: KSerializer<Value>,
|
||||||
|
unifiedRouter: UnifiedRouter
|
||||||
) {
|
) {
|
||||||
val keyValueSerializer = PairSerializer(keySerializer, valueSerializer)
|
val keyValueSerializer = PairSerializer(keySerializer, valueSerializer)
|
||||||
val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer))
|
val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer))
|
||||||
|
|
||||||
includeWebsocketHandling(
|
unifiedRouter.apply {
|
||||||
onNewValueRoute,
|
includeWebsocketHandling(
|
||||||
originalRepo.onNewValue,
|
onNewValueRoute,
|
||||||
keyValueSerializer
|
originalRepo.onNewValue,
|
||||||
)
|
keyValueSerializer
|
||||||
includeWebsocketHandling(
|
)
|
||||||
onValueRemovedRoute,
|
includeWebsocketHandling(
|
||||||
originalRepo.onValueRemoved,
|
onValueRemovedRoute,
|
||||||
keyValueSerializer
|
originalRepo.onValueRemoved,
|
||||||
)
|
keyValueSerializer
|
||||||
includeWebsocketHandling(
|
)
|
||||||
onDataClearedRoute,
|
includeWebsocketHandling(
|
||||||
originalRepo.onDataCleared,
|
onDataClearedRoute,
|
||||||
keySerializer
|
originalRepo.onDataCleared,
|
||||||
)
|
keySerializer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
post(addRoute) {
|
post(addRoute) {
|
||||||
val obj = call.uniload(keyValueMapSerializer)
|
unifiedRouter.apply {
|
||||||
|
val obj = uniload(keyValueMapSerializer)
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
Unit.serializer(),
|
Unit.serializer(),
|
||||||
originalRepo.add(obj)
|
originalRepo.add(obj)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post(removeRoute) {
|
post(removeRoute) {
|
||||||
val obj = call.uniload(
|
unifiedRouter.apply {
|
||||||
keyValueMapSerializer
|
val obj = uniload(keyValueMapSerializer)
|
||||||
)
|
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
Unit.serializer(),
|
Unit.serializer(),
|
||||||
originalRepo.remove(obj),
|
originalRepo.remove(obj),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post(clearRoute) {
|
post(clearRoute) {
|
||||||
val key = call.uniload(keySerializer)
|
unifiedRouter.apply {
|
||||||
|
val key = uniload(keySerializer)
|
||||||
|
|
||||||
call.unianswer(
|
unianswer(
|
||||||
Unit.serializer(),
|
Unit.serializer(),
|
||||||
originalRepo.clear(key),
|
originalRepo.clear(key),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
post(setRoute) {
|
||||||
|
unifiedRouter.apply {
|
||||||
|
val obj = uniload(keyValueMapSerializer)
|
||||||
|
|
||||||
|
unianswer(
|
||||||
|
Unit.serializer(),
|
||||||
|
originalRepo.set(obj)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes(
|
||||||
|
originalRepo: WriteOneToManyKeyValueRepo<Key, Value>,
|
||||||
|
keySerializer: KSerializer<Key>,
|
||||||
|
valueSerializer: KSerializer<Value>,
|
||||||
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
|
||||||
|
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
|
||||||
|
) = configureOneToManyWriteKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType))
|
||||||
|
@@ -18,6 +18,8 @@ String[] includes = [
|
|||||||
":ktor:client",
|
":ktor:client",
|
||||||
":coroutines",
|
":coroutines",
|
||||||
":android:recyclerview",
|
":android:recyclerview",
|
||||||
|
":android:alerts:common",
|
||||||
|
":android:alerts:recyclerview",
|
||||||
|
|
||||||
":dokka"
|
":dokka"
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user