mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-18 14:59:24 +00:00
Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
a7dce8fa78 | |||
ca73ff8e19 | |||
d01ad10d7d | |||
81041ee43c | |||
|
6e004c2ae4 | ||
0e2fac5b22 | |||
269da7f155 | |||
3cb6b73ee0 | |||
a938ee1efb | |||
6ea5e2e5a6 | |||
617dfb54e0 | |||
d23e005985 | |||
e5207f5bc5 | |||
c96cea8db0 | |||
0a8e71d76a | |||
cf1fd32b08 | |||
cc4224ea1f | |||
f4c148bc58 | |||
022297ad3f | |||
5180d6fc3e | |||
eeebbff70d | |||
afc6aeea15 | |||
486515eddd | |||
0e21699cd1 | |||
f1678ef7cf | |||
cea65fc76e | |||
c9e320b72a | |||
555956087d | |||
b3f468f901 | |||
f5f7511781 | |||
4be1d93f60 | |||
7d684608ef |
36
CHANGELOG.md
36
CHANGELOG.md
@@ -1,5 +1,41 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.17.7
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Android CoreKtx`: `1.9.0` -> `1.10.0`
|
||||||
|
* `Startup`:
|
||||||
|
* Add support of `linuxX64` and `mingwX64` platforms
|
||||||
|
|
||||||
|
## 0.17.6
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Kotlin`: `1.8.10` -> `1.8.20`
|
||||||
|
* `KSLog`: `1.0.0` -> `1.1.1`
|
||||||
|
* `Compose`: `1.3.1` -> `1.4.0`
|
||||||
|
* `Koin`: `3.3.2` -> `3.4.0`
|
||||||
|
* `RecyclerView`: `1.2.1` -> `1.3.0`
|
||||||
|
* `Fragment`: `1.5.5` -> `1.5.6`
|
||||||
|
* Experimentally (`!!!`) add `linuxX64` and `mingwX64` targets
|
||||||
|
|
||||||
|
## 0.17.5
|
||||||
|
|
||||||
|
* `Common`:
|
||||||
|
* Conversations of number primitives with bounds care
|
||||||
|
* `Repos`:
|
||||||
|
* `Common`:
|
||||||
|
* By default, `getAll` for repos will take all the size of repo as page size
|
||||||
|
* New extension for all built-in repos `maxPagePagination`
|
||||||
|
* All the repos got `getAll` functions
|
||||||
|
|
||||||
|
## 0.17.4
|
||||||
|
|
||||||
|
* `Serialization`:
|
||||||
|
* `Mapper`:
|
||||||
|
* Module inited
|
||||||
|
* `Versions`:
|
||||||
|
* `Compose`: `1.3.1-rc02` -> `1.3.1`
|
||||||
|
|
||||||
## 0.17.3
|
## 0.17.3
|
||||||
|
|
||||||
* `Common`:
|
* `Common`:
|
||||||
|
@@ -23,6 +23,7 @@ allprojects {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
google()
|
google()
|
||||||
maven { url "https://maven.pkg.jetbrains.space/public/p/compose/dev" }
|
maven { url "https://maven.pkg.jetbrains.space/public/p/compose/dev" }
|
||||||
|
maven { url "https://git.inmo.dev/api/packages/InsanusMokrassar/maven" }
|
||||||
}
|
}
|
||||||
|
|
||||||
// temporal crutch until legacy tests will be stabled or legacy target will be removed
|
// temporal crutch until legacy tests will be stabled or legacy target will be removed
|
||||||
|
@@ -20,5 +20,16 @@ kotlin {
|
|||||||
}
|
}
|
||||||
dependsOn jvmMain
|
dependsOn jvmMain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linuxX64Main {
|
||||||
|
dependencies {
|
||||||
|
api libs.okio
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mingwX64Main {
|
||||||
|
dependencies {
|
||||||
|
api libs.okio
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,28 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert [this] [Long] to [Int] with bounds of [Int.MIN_VALUE] and [Int.MAX_VALUE]
|
||||||
|
*/
|
||||||
|
fun Long.toCoercedInt(): Int = coerceIn(Int.MIN_VALUE.toLong(), Int.MAX_VALUE.toLong()).toInt()
|
||||||
|
/**
|
||||||
|
* Convert [this] [Long] to [Short] with bounds of [Short.MIN_VALUE] and [Short.MAX_VALUE]
|
||||||
|
*/
|
||||||
|
fun Long.toCoercedShort(): Short = coerceIn(Short.MIN_VALUE.toLong(), Short.MAX_VALUE.toLong()).toShort()
|
||||||
|
/**
|
||||||
|
* Convert [this] [Long] to [Byte] with bounds of [Byte.MIN_VALUE] and [Byte.MAX_VALUE]
|
||||||
|
*/
|
||||||
|
fun Long.toCoercedByte(): Byte = coerceIn(Byte.MIN_VALUE.toLong(), Byte.MAX_VALUE.toLong()).toByte()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert [this] [Int] to [Short] with bounds of [Short.MIN_VALUE] and [Short.MAX_VALUE]
|
||||||
|
*/
|
||||||
|
fun Int.toCoercedShort(): Short = coerceIn(Short.MIN_VALUE.toInt(), Short.MAX_VALUE.toInt()).toShort()
|
||||||
|
/**
|
||||||
|
* Convert [this] [Int] to [Byte] with bounds of [Byte.MIN_VALUE] and [Byte.MAX_VALUE]
|
||||||
|
*/
|
||||||
|
fun Int.toCoercedByte(): Byte = coerceIn(Byte.MIN_VALUE.toInt(), Byte.MAX_VALUE.toInt()).toByte()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert [this] [Short] to [Byte] with bounds of [Byte.MIN_VALUE] and [Byte.MAX_VALUE]
|
||||||
|
*/
|
||||||
|
fun Short.toCoercedByte(): Byte = coerceIn(Byte.MIN_VALUE.toShort(), Byte.MAX_VALUE.toShort()).toByte()
|
36
common/src/linuxX64Main/kotlin/ActualMPPFile.kt
Normal file
36
common/src/linuxX64Main/kotlin/ActualMPPFile.kt
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import okio.FileSystem
|
||||||
|
import okio.Path
|
||||||
|
import okio.use
|
||||||
|
|
||||||
|
actual typealias MPPFile = Path
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
actual val MPPFile.filename: FileName
|
||||||
|
get() = FileName(toString())
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
actual val MPPFile.filesize: Long
|
||||||
|
get() = FileSystem.SYSTEM.openReadOnly(this).use {
|
||||||
|
it.size()
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
actual val MPPFile.bytesAllocatorSync: ByteArrayAllocator
|
||||||
|
get() = {
|
||||||
|
FileSystem.SYSTEM.read(this) {
|
||||||
|
readByteArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
actual val MPPFile.bytesAllocator: SuspendByteArrayAllocator
|
||||||
|
get() = {
|
||||||
|
bytesAllocatorSync()
|
||||||
|
}
|
26
common/src/linuxX64Main/kotlin/fixed.kt
Normal file
26
common/src/linuxX64Main/kotlin/fixed.kt
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import kotlinx.cinterop.ByteVar
|
||||||
|
import kotlinx.cinterop.allocArray
|
||||||
|
import kotlinx.cinterop.memScoped
|
||||||
|
import kotlinx.cinterop.toKString
|
||||||
|
import platform.posix.snprintf
|
||||||
|
import platform.posix.sprintf
|
||||||
|
|
||||||
|
actual fun Float.fixed(signs: Int): Float {
|
||||||
|
return memScoped {
|
||||||
|
val buff = allocArray<ByteVar>(Float.SIZE_BYTES * 2)
|
||||||
|
|
||||||
|
sprintf(buff, "%.${signs}f", this@fixed)
|
||||||
|
buff.toKString().toFloat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun Double.fixed(signs: Int): Double {
|
||||||
|
return memScoped {
|
||||||
|
val buff = allocArray<ByteVar>(Double.SIZE_BYTES * 2)
|
||||||
|
|
||||||
|
sprintf(buff, "%.${signs}f", this@fixed)
|
||||||
|
buff.toKString().toDouble()
|
||||||
|
}
|
||||||
|
}
|
36
common/src/mingwX64Main/kotlin/ActualMPPFile.kt
Normal file
36
common/src/mingwX64Main/kotlin/ActualMPPFile.kt
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import okio.FileSystem
|
||||||
|
import okio.Path
|
||||||
|
import okio.use
|
||||||
|
|
||||||
|
actual typealias MPPFile = Path
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
actual val MPPFile.filename: FileName
|
||||||
|
get() = FileName(toString())
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
actual val MPPFile.filesize: Long
|
||||||
|
get() = FileSystem.SYSTEM.openReadOnly(this).use {
|
||||||
|
it.size()
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
actual val MPPFile.bytesAllocatorSync: ByteArrayAllocator
|
||||||
|
get() = {
|
||||||
|
FileSystem.SYSTEM.read(this) {
|
||||||
|
readByteArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
actual val MPPFile.bytesAllocator: SuspendByteArrayAllocator
|
||||||
|
get() = {
|
||||||
|
bytesAllocatorSync()
|
||||||
|
}
|
26
common/src/mingwX64Main/kotlin/fixed.kt
Normal file
26
common/src/mingwX64Main/kotlin/fixed.kt
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import kotlinx.cinterop.ByteVar
|
||||||
|
import kotlinx.cinterop.allocArray
|
||||||
|
import kotlinx.cinterop.memScoped
|
||||||
|
import kotlinx.cinterop.toKString
|
||||||
|
import platform.posix.snprintf
|
||||||
|
import platform.posix.sprintf
|
||||||
|
|
||||||
|
actual fun Float.fixed(signs: Int): Float {
|
||||||
|
return memScoped {
|
||||||
|
val buff = allocArray<ByteVar>(Float.SIZE_BYTES * 2)
|
||||||
|
|
||||||
|
sprintf(buff, "%.${signs}f", this@fixed)
|
||||||
|
buff.toKString().toFloat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun Double.fixed(signs: Int): Double {
|
||||||
|
return memScoped {
|
||||||
|
val buff = allocArray<ByteVar>(Double.SIZE_BYTES * 2)
|
||||||
|
|
||||||
|
sprintf(buff, "%.${signs}f", this@fixed)
|
||||||
|
buff.toKString().toDouble()
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,26 @@
|
|||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import org.w3c.dom.Image
|
||||||
|
|
||||||
|
suspend fun preloadImage(src: String): Image {
|
||||||
|
val image = Image()
|
||||||
|
image.src = src
|
||||||
|
|
||||||
|
val job = Job()
|
||||||
|
|
||||||
|
image.addEventListener("load", {
|
||||||
|
runCatching { job.complete() }
|
||||||
|
})
|
||||||
|
|
||||||
|
runCatchingSafely {
|
||||||
|
job.join()
|
||||||
|
}.onFailure {
|
||||||
|
if (it is CancellationException) {
|
||||||
|
image.src = ""
|
||||||
|
}
|
||||||
|
}.getOrThrow()
|
||||||
|
|
||||||
|
return image
|
||||||
|
}
|
@@ -11,6 +11,7 @@ kotlin {
|
|||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(":micro_utils.common")
|
api project(":micro_utils.common")
|
||||||
|
api libs.krypto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsMain {
|
jsMain {
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package dev.inmo.micro_utils.crypto
|
package dev.inmo.micro_utils.crypto
|
||||||
|
|
||||||
|
import com.soywiz.krypto.md5
|
||||||
|
|
||||||
typealias MD5 = String
|
typealias MD5 = String
|
||||||
|
|
||||||
expect fun SourceBytes.md5(): MD5
|
fun SourceBytes.md5(): MD5 = md5().hexLower
|
||||||
fun SourceString.md5(): MD5 = encodeToByteArray().md5()
|
fun SourceString.md5(): MD5 = encodeToByteArray().md5().hexLower
|
||||||
|
@@ -1,6 +0,0 @@
|
|||||||
package dev.inmo.micro_utils.crypto
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @suppress
|
|
||||||
*/
|
|
||||||
actual fun SourceBytes.md5(): MD5 = CryptoJS.MD5(decodeToString())
|
|
@@ -1,12 +0,0 @@
|
|||||||
package dev.inmo.micro_utils.crypto
|
|
||||||
|
|
||||||
import java.math.BigInteger
|
|
||||||
import java.security.MessageDigest
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @suppress
|
|
||||||
*/
|
|
||||||
actual fun SourceBytes.md5(): MD5 = BigInteger(
|
|
||||||
1,
|
|
||||||
MessageDigest.getInstance("MD5").digest(this)
|
|
||||||
).toString(16)
|
|
@@ -23,7 +23,7 @@ allprojects {
|
|||||||
mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle"
|
mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle"
|
||||||
mppProjectWithSerializationAndComposePresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerializationAndCompose.gradle"
|
mppProjectWithSerializationAndComposePresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerializationAndCompose.gradle"
|
||||||
mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle"
|
mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle"
|
||||||
mppJsAndJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJsAndJavaProject.gradle"
|
mppJvmJsLinuxMingwProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJvmJsLinuxMingwProject.gradle"
|
||||||
mppAndroidProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppAndroidProject.gradle"
|
mppAndroidProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppAndroidProject.gradle"
|
||||||
|
|
||||||
defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle"
|
defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle"
|
||||||
|
@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
|
|||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.17.3
|
version=0.17.7
|
||||||
android_code_version=185
|
android_code_version=189
|
||||||
|
@@ -1,34 +1,36 @@
|
|||||||
[versions]
|
[versions]
|
||||||
|
|
||||||
kt = "1.8.10"
|
kt = "1.8.20"
|
||||||
kt-serialization = "1.5.0"
|
kt-serialization = "1.5.0"
|
||||||
kt-coroutines = "1.6.4"
|
kt-coroutines = "1.6.4"
|
||||||
|
|
||||||
kslog = "1.0.0"
|
kslog = "1.1.1"
|
||||||
|
|
||||||
jb-compose = "1.3.1-rc01"
|
jb-compose = "1.4.0"
|
||||||
jb-exposed = "0.41.1"
|
jb-exposed = "0.41.1"
|
||||||
jb-dokka = "1.7.20"
|
jb-dokka = "1.8.10"
|
||||||
|
|
||||||
klock = "3.4.0"
|
korlibs = "3.4.0"
|
||||||
uuid = "0.7.0"
|
uuid = "0.7.0"
|
||||||
|
|
||||||
ktor = "2.2.4"
|
ktor = "2.2.4"
|
||||||
|
|
||||||
gh-release = "2.4.1"
|
gh-release = "2.4.1"
|
||||||
|
|
||||||
koin = "3.3.2"
|
koin = "3.4.0"
|
||||||
|
|
||||||
ksp = "1.8.10-1.0.9"
|
okio = "3.3.0"
|
||||||
kotlin-poet = "1.12.0"
|
|
||||||
|
ksp = "1.8.20-1.0.11"
|
||||||
|
kotlin-poet = "1.13.0"
|
||||||
|
|
||||||
android-gradle = "7.3.1"
|
android-gradle = "7.3.1"
|
||||||
dexcount = "4.0.0"
|
dexcount = "4.0.0"
|
||||||
|
|
||||||
android-coreKtx = "1.9.0"
|
android-coreKtx = "1.10.0"
|
||||||
android-recyclerView = "1.2.1"
|
android-recyclerView = "1.3.0"
|
||||||
android-appCompat = "1.6.1"
|
android-appCompat = "1.6.1"
|
||||||
android-fragment = "1.5.5"
|
android-fragment = "1.5.6"
|
||||||
android-espresso = "3.5.1"
|
android-espresso = "3.5.1"
|
||||||
android-test = "1.1.5"
|
android-test = "1.1.5"
|
||||||
|
|
||||||
@@ -67,7 +69,8 @@ ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negoti
|
|||||||
|
|
||||||
kslog = { module = "dev.inmo:kslog", version.ref = "kslog" }
|
kslog = { module = "dev.inmo:kslog", version.ref = "kslog" }
|
||||||
|
|
||||||
klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" }
|
klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "korlibs" }
|
||||||
|
krypto = { module = "com.soywiz.korlibs.krypto:krypto", version.ref = "korlibs" }
|
||||||
uuid = { module = "com.benasher44:uuid", version.ref = "uuid" }
|
uuid = { module = "com.benasher44:uuid", version.ref = "uuid" }
|
||||||
koin = { module = "io.insert-koin:koin-core", version.ref = "koin" }
|
koin = { module = "io.insert-koin:koin-core", version.ref = "koin" }
|
||||||
|
|
||||||
@@ -91,6 +94,8 @@ kt-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref
|
|||||||
kotlin-poet = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlin-poet" }
|
kotlin-poet = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlin-poet" }
|
||||||
ksp = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" }
|
ksp = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" }
|
||||||
|
|
||||||
|
okio = { module = "com.squareup.okio:okio", version.ref = "okio" }
|
||||||
|
|
||||||
# Buildscript
|
# Buildscript
|
||||||
|
|
||||||
buildscript-kt-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kt" }
|
buildscript-kt-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kt" }
|
||||||
|
@@ -18,5 +18,17 @@ kotlin {
|
|||||||
androidMain {
|
androidMain {
|
||||||
dependsOn jvmMain
|
dependsOn jvmMain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linuxX64Main {
|
||||||
|
dependencies {
|
||||||
|
api internalProject("micro_utils.mime_types")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mingwX64Main {
|
||||||
|
dependencies {
|
||||||
|
api internalProject("micro_utils.mime_types")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,10 @@
|
|||||||
package dev.inmo.micro_utils.ktor.client
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
import dev.inmo.micro_utils.common.MPPFile
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.common.filesize
|
||||||
|
import dev.inmo.micro_utils.ktor.common.input
|
||||||
import io.ktor.client.request.forms.InputProvider
|
import io.ktor.client.request.forms.InputProvider
|
||||||
|
|
||||||
expect suspend fun MPPFile.inputProvider(): InputProvider
|
fun MPPFile.inputProvider(): InputProvider = InputProvider(filesize) {
|
||||||
|
input()
|
||||||
|
}
|
||||||
|
@@ -1,11 +0,0 @@
|
|||||||
package dev.inmo.micro_utils.ktor.client
|
|
||||||
|
|
||||||
import dev.inmo.micro_utils.common.*
|
|
||||||
import io.ktor.client.request.forms.InputProvider
|
|
||||||
import io.ktor.utils.io.core.ByteReadPacket
|
|
||||||
|
|
||||||
actual suspend fun MPPFile.inputProvider(): InputProvider = bytes().let {
|
|
||||||
InputProvider(it.size.toLong()) {
|
|
||||||
ByteReadPacket(it)
|
|
||||||
}
|
|
||||||
}
|
|
@@ -7,5 +7,3 @@ import io.ktor.utils.io.streams.asInput
|
|||||||
fun MPPFile.inputProviderSync(): InputProvider = InputProvider(length()) {
|
fun MPPFile.inputProviderSync(): InputProvider = InputProvider(length()) {
|
||||||
inputStream().asInput()
|
inputStream().asInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
actual suspend fun MPPFile.inputProvider(): InputProvider = inputProviderSync()
|
|
||||||
|
40
ktor/client/src/linuxX64Main/kotlin/ActualTemporalUpload.kt
Normal file
40
ktor/client/src/linuxX64Main/kotlin/ActualTemporalUpload.kt
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.common.filename
|
||||||
|
import dev.inmo.micro_utils.ktor.common.TemporalFileId
|
||||||
|
import dev.inmo.micro_utils.mime_types.getMimeTypeOrAny
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.plugins.onUpload
|
||||||
|
import io.ktor.client.request.forms.formData
|
||||||
|
import io.ktor.client.request.forms.submitFormWithBinaryData
|
||||||
|
import io.ktor.client.statement.bodyAsText
|
||||||
|
import io.ktor.http.Headers
|
||||||
|
import io.ktor.http.HttpHeaders
|
||||||
|
|
||||||
|
internal val MPPFile.mimeType: String
|
||||||
|
get() = getMimeTypeOrAny(filename.extension).raw
|
||||||
|
|
||||||
|
actual suspend fun HttpClient.tempUpload(
|
||||||
|
fullTempUploadDraftPath: String,
|
||||||
|
file: MPPFile,
|
||||||
|
onUpload: OnUploadCallback
|
||||||
|
): TemporalFileId {
|
||||||
|
val inputProvider = file.inputProvider()
|
||||||
|
val fileId = submitFormWithBinaryData(
|
||||||
|
fullTempUploadDraftPath,
|
||||||
|
formData = formData {
|
||||||
|
append(
|
||||||
|
"data",
|
||||||
|
inputProvider,
|
||||||
|
Headers.build {
|
||||||
|
append(HttpHeaders.ContentType, file.mimeType)
|
||||||
|
append(HttpHeaders.ContentDisposition, "filename=\"${file.filename.string}\"")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
onUpload(onUpload)
|
||||||
|
}.bodyAsText()
|
||||||
|
return TemporalFileId(fileId)
|
||||||
|
}
|
107
ktor/client/src/linuxX64Main/kotlin/ActualUniUpload.kt
Normal file
107
ktor/client/src/linuxX64Main/kotlin/ActualUniUpload.kt
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.common.Progress
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.engine.mergeHeaders
|
||||||
|
import io.ktor.client.plugins.onUpload
|
||||||
|
import io.ktor.client.request.HttpRequestBuilder
|
||||||
|
import io.ktor.client.request.forms.InputProvider
|
||||||
|
import io.ktor.client.request.forms.formData
|
||||||
|
import io.ktor.client.request.forms.submitForm
|
||||||
|
import io.ktor.client.request.forms.submitFormWithBinaryData
|
||||||
|
import io.ktor.client.request.headers
|
||||||
|
import io.ktor.client.statement.bodyAsText
|
||||||
|
import io.ktor.http.Headers
|
||||||
|
import io.ktor.http.HttpHeaders
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.http.Parameters
|
||||||
|
import io.ktor.http.content.PartData
|
||||||
|
import kotlinx.serialization.DeserializationStrategy
|
||||||
|
import kotlinx.serialization.InternalSerializationApi
|
||||||
|
import kotlinx.serialization.SerializationStrategy
|
||||||
|
import kotlinx.serialization.StringFormat
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.serializer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will execute submitting of multipart data request
|
||||||
|
*
|
||||||
|
* @param data [Map] where keys will be used as names for multipart parts and values as values. If you will pass
|
||||||
|
* [dev.inmo.micro_utils.common.MPPFile] (File from JS or JVM platform). Also you may pass [UniUploadFileInfo] as value
|
||||||
|
* in case you wish to pass other source of multipart binary data than regular file
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
@OptIn(InternalSerializationApi::class)
|
||||||
|
actual suspend fun <T> HttpClient.uniUpload(
|
||||||
|
url: String,
|
||||||
|
data: Map<String, Any>,
|
||||||
|
resultDeserializer: DeserializationStrategy<T>,
|
||||||
|
headers: Headers,
|
||||||
|
stringFormat: StringFormat,
|
||||||
|
onUpload: OnUploadCallback
|
||||||
|
): T? {
|
||||||
|
val withBinary = data.values.any { it is MPPFile || it is UniUploadFileInfo }
|
||||||
|
|
||||||
|
val formData = formData {
|
||||||
|
for (k in data.keys) {
|
||||||
|
val v = data[k] ?: continue
|
||||||
|
when (v) {
|
||||||
|
is MPPFile -> append(
|
||||||
|
k,
|
||||||
|
v.inputProvider(),
|
||||||
|
Headers.build {
|
||||||
|
append(HttpHeaders.ContentType, v.mimeType)
|
||||||
|
append(HttpHeaders.ContentDisposition, "filename=\"${v.name}\"")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
is UniUploadFileInfo -> append(
|
||||||
|
k,
|
||||||
|
InputProvider(block = v.inputAllocator),
|
||||||
|
Headers.build {
|
||||||
|
append(HttpHeaders.ContentType, v.mimeType)
|
||||||
|
append(HttpHeaders.ContentDisposition, "filename=\"${v.fileName.name}\"")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else -> append(
|
||||||
|
k,
|
||||||
|
stringFormat.encodeToString(v::class.serializer() as SerializationStrategy<in Any>, v)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val requestBuilder: HttpRequestBuilder.() -> Unit = {
|
||||||
|
headers {
|
||||||
|
appendAll(headers)
|
||||||
|
}
|
||||||
|
onUpload { bytesSentTotal, contentLength ->
|
||||||
|
onUpload(bytesSentTotal, contentLength)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val response = if (withBinary) {
|
||||||
|
submitFormWithBinaryData(
|
||||||
|
url,
|
||||||
|
formData,
|
||||||
|
block = requestBuilder
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
submitForm(
|
||||||
|
url,
|
||||||
|
Parameters.build {
|
||||||
|
for (it in formData) {
|
||||||
|
val formItem = (it as PartData.FormItem)
|
||||||
|
append(it.name!!, it.value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
block = requestBuilder
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (response.status == HttpStatusCode.OK) {
|
||||||
|
stringFormat.decodeFromString(resultDeserializer, response.bodyAsText())
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
40
ktor/client/src/mingwX64Main/kotlin/ActualTemporalUpload.kt
Normal file
40
ktor/client/src/mingwX64Main/kotlin/ActualTemporalUpload.kt
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.common.filename
|
||||||
|
import dev.inmo.micro_utils.ktor.common.TemporalFileId
|
||||||
|
import dev.inmo.micro_utils.mime_types.getMimeTypeOrAny
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.plugins.onUpload
|
||||||
|
import io.ktor.client.request.forms.formData
|
||||||
|
import io.ktor.client.request.forms.submitFormWithBinaryData
|
||||||
|
import io.ktor.client.statement.bodyAsText
|
||||||
|
import io.ktor.http.Headers
|
||||||
|
import io.ktor.http.HttpHeaders
|
||||||
|
|
||||||
|
internal val MPPFile.mimeType: String
|
||||||
|
get() = getMimeTypeOrAny(filename.extension).raw
|
||||||
|
|
||||||
|
actual suspend fun HttpClient.tempUpload(
|
||||||
|
fullTempUploadDraftPath: String,
|
||||||
|
file: MPPFile,
|
||||||
|
onUpload: OnUploadCallback
|
||||||
|
): TemporalFileId {
|
||||||
|
val inputProvider = file.inputProvider()
|
||||||
|
val fileId = submitFormWithBinaryData(
|
||||||
|
fullTempUploadDraftPath,
|
||||||
|
formData = formData {
|
||||||
|
append(
|
||||||
|
"data",
|
||||||
|
inputProvider,
|
||||||
|
Headers.build {
|
||||||
|
append(HttpHeaders.ContentType, file.mimeType)
|
||||||
|
append(HttpHeaders.ContentDisposition, "filename=\"${file.filename.string}\"")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
onUpload(onUpload)
|
||||||
|
}.bodyAsText()
|
||||||
|
return TemporalFileId(fileId)
|
||||||
|
}
|
107
ktor/client/src/mingwX64Main/kotlin/ActualUniUpload.kt
Normal file
107
ktor/client/src/mingwX64Main/kotlin/ActualUniUpload.kt
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.common.Progress
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.engine.mergeHeaders
|
||||||
|
import io.ktor.client.plugins.onUpload
|
||||||
|
import io.ktor.client.request.HttpRequestBuilder
|
||||||
|
import io.ktor.client.request.forms.InputProvider
|
||||||
|
import io.ktor.client.request.forms.formData
|
||||||
|
import io.ktor.client.request.forms.submitForm
|
||||||
|
import io.ktor.client.request.forms.submitFormWithBinaryData
|
||||||
|
import io.ktor.client.request.headers
|
||||||
|
import io.ktor.client.statement.bodyAsText
|
||||||
|
import io.ktor.http.Headers
|
||||||
|
import io.ktor.http.HttpHeaders
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.http.Parameters
|
||||||
|
import io.ktor.http.content.PartData
|
||||||
|
import kotlinx.serialization.DeserializationStrategy
|
||||||
|
import kotlinx.serialization.InternalSerializationApi
|
||||||
|
import kotlinx.serialization.SerializationStrategy
|
||||||
|
import kotlinx.serialization.StringFormat
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.serializer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will execute submitting of multipart data request
|
||||||
|
*
|
||||||
|
* @param data [Map] where keys will be used as names for multipart parts and values as values. If you will pass
|
||||||
|
* [dev.inmo.micro_utils.common.MPPFile] (File from JS or JVM platform). Also you may pass [UniUploadFileInfo] as value
|
||||||
|
* in case you wish to pass other source of multipart binary data than regular file
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
@OptIn(InternalSerializationApi::class)
|
||||||
|
actual suspend fun <T> HttpClient.uniUpload(
|
||||||
|
url: String,
|
||||||
|
data: Map<String, Any>,
|
||||||
|
resultDeserializer: DeserializationStrategy<T>,
|
||||||
|
headers: Headers,
|
||||||
|
stringFormat: StringFormat,
|
||||||
|
onUpload: OnUploadCallback
|
||||||
|
): T? {
|
||||||
|
val withBinary = data.values.any { it is MPPFile || it is UniUploadFileInfo }
|
||||||
|
|
||||||
|
val formData = formData {
|
||||||
|
for (k in data.keys) {
|
||||||
|
val v = data[k] ?: continue
|
||||||
|
when (v) {
|
||||||
|
is MPPFile -> append(
|
||||||
|
k,
|
||||||
|
v.inputProvider(),
|
||||||
|
Headers.build {
|
||||||
|
append(HttpHeaders.ContentType, v.mimeType)
|
||||||
|
append(HttpHeaders.ContentDisposition, "filename=\"${v.name}\"")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
is UniUploadFileInfo -> append(
|
||||||
|
k,
|
||||||
|
InputProvider(block = v.inputAllocator),
|
||||||
|
Headers.build {
|
||||||
|
append(HttpHeaders.ContentType, v.mimeType)
|
||||||
|
append(HttpHeaders.ContentDisposition, "filename=\"${v.fileName.name}\"")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else -> append(
|
||||||
|
k,
|
||||||
|
stringFormat.encodeToString(v::class.serializer() as SerializationStrategy<in Any>, v)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val requestBuilder: HttpRequestBuilder.() -> Unit = {
|
||||||
|
headers {
|
||||||
|
appendAll(headers)
|
||||||
|
}
|
||||||
|
onUpload { bytesSentTotal, contentLength ->
|
||||||
|
onUpload(bytesSentTotal, contentLength)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val response = if (withBinary) {
|
||||||
|
submitFormWithBinaryData(
|
||||||
|
url,
|
||||||
|
formData,
|
||||||
|
block = requestBuilder
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
submitForm(
|
||||||
|
url,
|
||||||
|
Parameters.build {
|
||||||
|
for (it in formData) {
|
||||||
|
val formItem = (it as PartData.FormItem)
|
||||||
|
append(it.name!!, it.value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
block = requestBuilder
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (response.status == HttpStatusCode.OK) {
|
||||||
|
stringFormat.decodeFromString(resultDeserializer, response.bodyAsText())
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
11
ktor/common/src/linuxX64Main/kotlin/ActualMPPFileInput.kt
Normal file
11
ktor/common/src/linuxX64Main/kotlin/ActualMPPFileInput.kt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.common
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.common.bytesAllocatorSync
|
||||||
|
import io.ktor.utils.io.core.ByteReadPacket
|
||||||
|
import io.ktor.utils.io.core.Input
|
||||||
|
|
||||||
|
actual fun MPPFile.input(): Input {
|
||||||
|
return ByteReadPacket(bytesAllocatorSync())
|
||||||
|
}
|
||||||
|
|
10
ktor/common/src/mingwX64Main/kotlin/ActualMPPFileInput.kt
Normal file
10
ktor/common/src/mingwX64Main/kotlin/ActualMPPFileInput.kt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.common
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.MPPFile
|
||||||
|
import dev.inmo.micro_utils.common.bytesAllocatorSync
|
||||||
|
import io.ktor.utils.io.core.ByteReadPacket
|
||||||
|
import io.ktor.utils.io.core.Input
|
||||||
|
|
||||||
|
actual fun MPPFile.input(): Input {
|
||||||
|
return ByteReadPacket(bytesAllocatorSync())
|
||||||
|
}
|
@@ -1,3 +1,5 @@
|
|||||||
|
import math
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
@@ -17,33 +19,45 @@ def fix_name(category, raw_name):
|
|||||||
result += out1
|
result += out1
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def remove_prefix(text, prefix):
|
||||||
|
if text.startswith(prefix):
|
||||||
|
return text[len(prefix):]
|
||||||
|
return text # or whatever
|
||||||
|
|
||||||
|
def extensionPreparationFun(extension):
|
||||||
|
return "\"%s\"" % (remove_prefix(extension, "."))
|
||||||
|
|
||||||
# https://www.freeformatter.com/mime-types-list.html
|
# https://www.freeformatter.com/mime-types-list.html
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
df = pd.read_html(open('table.html', 'r'))
|
df = pd.read_html(open('local.table.html', 'r'))
|
||||||
mimes = []
|
mimes = []
|
||||||
for row in df[0].drop_duplicates(subset=['MIME Type / Internet Media Type'], keep='first').iterrows():
|
for row in df[0].drop_duplicates(subset=['MIME Type / Internet Media Type'], keep='first').iterrows():
|
||||||
mime = row[1][1]
|
mime = row[1][1]
|
||||||
|
extensions = list()
|
||||||
|
if isinstance(row[1][2], str):
|
||||||
|
extensions = list(map(extensionPreparationFun, row[1][2].split(", ")))
|
||||||
mime_category = mime.split('/', 1)[0]
|
mime_category = mime.split('/', 1)[0]
|
||||||
mime_name = mime.split('/', 1)[1]
|
mime_name = mime.split('/', 1)[1]
|
||||||
mimes.append({
|
mimes.append([
|
||||||
'mime_category': mime_category,
|
mime_category,
|
||||||
'mime_name': mime_name,
|
mime_name,
|
||||||
})
|
extensions
|
||||||
|
])
|
||||||
|
|
||||||
# codegen
|
# codegen
|
||||||
|
|
||||||
mimes.sort(key=lambda x: x['mime_category'])
|
mimes.sort(key=lambda x: x[0])
|
||||||
grouped = itertools.groupby(mimes, lambda x: x['mime_category'])
|
grouped = itertools.groupby(mimes, lambda x: x[0])
|
||||||
code = ''
|
code = ''
|
||||||
code2 = 'internal val knownMimeTypes: Set<MimeType> = setOf(\n'
|
code2 = 'internal val knownMimeTypes: Set<MimeType> = setOf(\n'
|
||||||
code2 += ' KnownMimeTypes.Any,\n'
|
code2 += ' KnownMimeTypes.Any,\n'
|
||||||
for key, group in grouped:
|
for key, group in grouped:
|
||||||
group_name = fix_name(group, key)
|
group_name = fix_name(group, key)
|
||||||
code += '@Serializable(MimeTypeSerializer::class)\nsealed class %s(raw: String) : MimeType, KnownMimeTypes(raw) {\n' % group_name
|
code += '@Serializable(MimeTypeSerializer::class)\nsealed class %s(raw: String, extensions: Array<String> = emptyArray()) : MimeType, KnownMimeTypes(raw, extensions) {\n' % group_name
|
||||||
code += ' @Serializable(MimeTypeSerializer::class)\n object Any: %s ("%s/*")\n' % (group_name, key)
|
code += ' @Serializable(MimeTypeSerializer::class)\n object Any: %s ("%s/*")\n' % (group_name, key)
|
||||||
for mime in group:
|
for mime in group:
|
||||||
name = fix_name(mime['mime_category'], mime['mime_name'])
|
name = fix_name(mime[0], mime[1])
|
||||||
code += ' @Serializable(MimeTypeSerializer::class)\n object %s: %s ("%s/%s")\n' % (name, group_name, mime['mime_category'], mime['mime_name'])
|
code += ' @Serializable(MimeTypeSerializer::class)\n object %s: %s ("%s/%s", arrayOf(%s))\n' % (name, group_name, mime[0], mime[1], ", ".join(mime[2]))
|
||||||
code2 += ' KnownMimeTypes.%s.%s,\n' % (group_name, name)
|
code2 += ' KnownMimeTypes.%s.%s,\n' % (group_name, name)
|
||||||
code += '}\n\n'
|
code += '}\n\n'
|
||||||
code2 += ')\n'
|
code2 += ')\n'
|
||||||
|
@@ -0,0 +1,24 @@
|
|||||||
|
package dev.inmo.micro_utils.mime_types
|
||||||
|
|
||||||
|
val mimeTypesByExtensions: Map<String, Array<MimeType>> by lazy {
|
||||||
|
val extensionsMap = mutableMapOf<String, MutableList<MimeType>>()
|
||||||
|
|
||||||
|
knownMimeTypes.forEach { mimeType ->
|
||||||
|
mimeType.extensions.forEach {
|
||||||
|
extensionsMap.getOrPut(it) { mutableListOf() }.add(mimeType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extensionsMap.mapValues {
|
||||||
|
it.value.toTypedArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun getMimeType(
|
||||||
|
stringWithExtension: String,
|
||||||
|
selector: (Array<MimeType>) -> MimeType? = { it.firstOrNull() }
|
||||||
|
) = mimeTypesByExtensions[stringWithExtension.takeLastWhile { it != '.' }] ?.takeIf { it.isNotEmpty() } ?.let(selector)
|
||||||
|
inline fun getMimeTypeOrAny(
|
||||||
|
stringWithExtension: String,
|
||||||
|
selector: (Array<MimeType>) -> MimeType? = { it.firstOrNull() }
|
||||||
|
) = getMimeType(stringWithExtension, selector) ?: KnownMimeTypes.Any
|
File diff suppressed because it is too large
Load Diff
@@ -5,4 +5,6 @@ import kotlinx.serialization.Serializable
|
|||||||
@Serializable(MimeTypeSerializer::class)
|
@Serializable(MimeTypeSerializer::class)
|
||||||
interface MimeType {
|
interface MimeType {
|
||||||
val raw: String
|
val raw: String
|
||||||
|
val extensions: Array<String>
|
||||||
|
get() = emptyArray()
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,8 @@ kotlin {
|
|||||||
browser()
|
browser()
|
||||||
nodejs()
|
nodejs()
|
||||||
}
|
}
|
||||||
|
linuxX64()
|
||||||
|
mingwX64()
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
@@ -18,6 +18,8 @@ kotlin {
|
|||||||
android {
|
android {
|
||||||
publishAllLibraryVariants()
|
publishAllLibraryVariants()
|
||||||
}
|
}
|
||||||
|
linuxX64()
|
||||||
|
mingwX64()
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
@@ -50,6 +52,16 @@ kotlin {
|
|||||||
implementation libs.android.espresso
|
implementation libs.android.espresso
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mingwX64Test {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin('test-junit')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
linuxX64Test {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin('test-junit')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
androidMain.dependsOn jvmMain
|
androidMain.dependsOn jvmMain
|
||||||
}
|
}
|
||||||
|
6
renovate.json
Normal file
6
renovate.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"config:base"
|
||||||
|
]
|
||||||
|
}
|
@@ -2,6 +2,7 @@ package dev.inmo.micro_utils.repos.cache
|
|||||||
|
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
||||||
|
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
@@ -15,6 +16,12 @@ open class ReadCRUDCacheRepo<ObjectType, IdType>(
|
|||||||
kvCache.set(id, it)
|
kvCache.set(id, it)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<IdType, ObjectType> {
|
||||||
|
return kvCache.getAll().takeIf { it.size.toLong() == count() } ?: parentRepo.getAll().also {
|
||||||
|
kvCache.actualizeAll(true) { it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id)
|
override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id)
|
||||||
|
|
||||||
override suspend fun invalidate() = kvCache.clear()
|
override suspend fun invalidate() = kvCache.clear()
|
||||||
|
@@ -24,6 +24,12 @@ open class ReadKeyValueCacheRepo<Key,Value>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<Key, Value> = kvCache.getAll().takeIf {
|
||||||
|
it.size.toLong() == count()
|
||||||
|
} ?: parentRepo.getAll().also {
|
||||||
|
kvCache.set(it)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun invalidate() = kvCache.clear()
|
override suspend fun invalidate() = kvCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -52,6 +52,14 @@ open class AutoRecacheReadCRUDRepo<RegisteredObject, Id>(
|
|||||||
kvCache.contains(id)
|
kvCache.contains(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<Id, RegisteredObject> = actionWrapper.wrap {
|
||||||
|
originalRepo.getAll()
|
||||||
|
}.onSuccess {
|
||||||
|
kvCache.actualizeAll(clear = true) { it }
|
||||||
|
}.getOrElse {
|
||||||
|
kvCache.getAll()
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun count(): Long = actionWrapper.wrap {
|
override suspend fun count(): Long = actionWrapper.wrap {
|
||||||
originalRepo.count()
|
originalRepo.count()
|
||||||
}.getOrElse {
|
}.getOrElse {
|
||||||
|
@@ -52,6 +52,14 @@ open class AutoRecacheReadKeyValueRepo<Id, RegisteredObject>(
|
|||||||
kvCache.contains(key)
|
kvCache.contains(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<Id, RegisteredObject> = actionWrapper.wrap {
|
||||||
|
originalRepo.getAll()
|
||||||
|
}.onSuccess {
|
||||||
|
kvCache.actualizeAll(clear = true) { it }
|
||||||
|
}.getOrElse {
|
||||||
|
kvCache.getAll()
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun count(): Long = actionWrapper.wrap {
|
override suspend fun count(): Long = actionWrapper.wrap {
|
||||||
originalRepo.count()
|
originalRepo.count()
|
||||||
}.getOrElse {
|
}.getOrElse {
|
||||||
|
@@ -58,6 +58,12 @@ open class FullReadCRUDCacheRepo<ObjectType, IdType>(
|
|||||||
{ if (it) parentRepo.getById(id) ?.let { set(id, it) } }
|
{ if (it) parentRepo.getById(id) ?.let { set(id, it) } }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<IdType, ObjectType> = doOrTakeAndActualize(
|
||||||
|
{ getAll().takeIf { it.isNotEmpty() }.optionalOrAbsentIfNull },
|
||||||
|
{ getAll() },
|
||||||
|
{ kvCache.actualizeAll(clear = true) { it } }
|
||||||
|
)
|
||||||
|
|
||||||
override suspend fun getById(id: IdType): ObjectType? = doOrTakeAndActualize(
|
override suspend fun getById(id: IdType): ObjectType? = doOrTakeAndActualize(
|
||||||
{ get(id) ?.optional ?: Optional.absent() },
|
{ get(id) ?.optional ?: Optional.absent() },
|
||||||
{ getById(id) },
|
{ getById(id) },
|
||||||
|
@@ -9,7 +9,6 @@ import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
|||||||
import dev.inmo.micro_utils.repos.pagination.getAll
|
import dev.inmo.micro_utils.repos.pagination.getAll
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
open class FullReadKeyValueCacheRepo<Key,Value>(
|
open class FullReadKeyValueCacheRepo<Key,Value>(
|
||||||
@@ -59,6 +58,12 @@ open class FullReadKeyValueCacheRepo<Key,Value>(
|
|||||||
{ if (it) parentRepo.get(key) ?.also { kvCache.set(key, it) } }
|
{ if (it) parentRepo.get(key) ?.also { kvCache.set(key, it) } }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<Key, Value> = doOrTakeAndActualize(
|
||||||
|
{ getAll().takeIf { it.isNotEmpty() }.optionalOrAbsentIfNull },
|
||||||
|
{ getAll() },
|
||||||
|
{ kvCache.actualizeAll(clear = true) { it } }
|
||||||
|
)
|
||||||
|
|
||||||
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = doOrTakeAndActualize(
|
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = doOrTakeAndActualize(
|
||||||
{ keys(pagination, reversed).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull },
|
{ keys(pagination, reversed).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull },
|
||||||
{ keys(pagination, reversed) },
|
{ keys(pagination, reversed) },
|
||||||
|
@@ -28,7 +28,7 @@ suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
|
|||||||
clear: Boolean = true,
|
clear: Boolean = true,
|
||||||
) {
|
) {
|
||||||
actualizeAll(clear) {
|
actualizeAll(clear) {
|
||||||
repo.getAll { keys(it) }.toMap()
|
repo.getAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ suspend inline fun <K, V> KVCache<K, List<V>>.actualizeAll(
|
|||||||
clear: Boolean = true,
|
clear: Boolean = true,
|
||||||
) {
|
) {
|
||||||
actualizeAll(clear) {
|
actualizeAll(clear) {
|
||||||
repo.getAll { keys(it) }.toMap()
|
repo.getAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,8 +46,6 @@ suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
|
|||||||
clear: Boolean = true,
|
clear: Boolean = true,
|
||||||
) {
|
) {
|
||||||
actualizeAll(clear) {
|
actualizeAll(clear) {
|
||||||
repo.getAllByWithNextPaging {
|
repo.getAll()
|
||||||
getIdsByPagination(it)
|
|
||||||
}.mapNotNull { it to (repo.getById(it) ?: return@mapNotNull null) }.toMap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,10 @@ package dev.inmo.micro_utils.repos
|
|||||||
|
|
||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
import dev.inmo.micro_utils.pagination.utils.doAllWithCurrentPaging
|
import dev.inmo.micro_utils.pagination.utils.doAllWithCurrentPaging
|
||||||
|
import dev.inmo.micro_utils.pagination.utils.getAllByWithNextPaging
|
||||||
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
|
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
|
||||||
import dev.inmo.micro_utils.pagination.utils.paginate
|
import dev.inmo.micro_utils.pagination.utils.paginate
|
||||||
|
import dev.inmo.micro_utils.repos.pagination.maxPagePagination
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,6 +53,16 @@ interface ReadKeyValueRepo<Key, Value> : Repo {
|
|||||||
*/
|
*/
|
||||||
suspend fun contains(key: Key): Boolean
|
suspend fun contains(key: Key): Boolean
|
||||||
|
|
||||||
|
suspend fun getAll(): Map<Key, Value> = getAllByWithNextPaging(maxPagePagination()) {
|
||||||
|
keys(it).let {
|
||||||
|
it.changeResultsUnchecked(
|
||||||
|
it.results.mapNotNull {
|
||||||
|
it to (get(it) ?: return@mapNotNull null)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return count of all collection objects
|
* @return count of all collection objects
|
||||||
*/
|
*/
|
||||||
|
@@ -2,6 +2,9 @@ package dev.inmo.micro_utils.repos
|
|||||||
|
|
||||||
import dev.inmo.micro_utils.pagination.Pagination
|
import dev.inmo.micro_utils.pagination.Pagination
|
||||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||||
|
import dev.inmo.micro_utils.pagination.changeResultsUnchecked
|
||||||
|
import dev.inmo.micro_utils.pagination.utils.getAllWithCurrentPaging
|
||||||
|
import dev.inmo.micro_utils.repos.pagination.maxPagePagination
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface ReadCRUDRepo<ObjectType, IdType> : Repo {
|
interface ReadCRUDRepo<ObjectType, IdType> : Repo {
|
||||||
@@ -9,6 +12,14 @@ interface ReadCRUDRepo<ObjectType, IdType> : Repo {
|
|||||||
suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType>
|
suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType>
|
||||||
suspend fun getById(id: IdType): ObjectType?
|
suspend fun getById(id: IdType): ObjectType?
|
||||||
suspend fun contains(id: IdType): Boolean
|
suspend fun contains(id: IdType): Boolean
|
||||||
|
suspend fun getAll(): Map<IdType, ObjectType> = getAllWithCurrentPaging(maxPagePagination()) {
|
||||||
|
getIdsByPagination(it).let {
|
||||||
|
it.changeResultsUnchecked(
|
||||||
|
it.results.mapNotNull { it to (getById(it) ?: return@mapNotNull null) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
suspend fun count(): Long
|
suspend fun count(): Long
|
||||||
}
|
}
|
||||||
typealias ReadStandardCRUDRepo<ObjectType, IdType> = ReadCRUDRepo<ObjectType, IdType>
|
typealias ReadStandardCRUDRepo<ObjectType, IdType> = ReadCRUDRepo<ObjectType, IdType>
|
||||||
|
@@ -32,6 +32,10 @@ open class MapperReadCRUDRepo<FromId, FromRegistered, ToId, ToRegistered>(
|
|||||||
|
|
||||||
override suspend fun contains(id: FromId): Boolean = to.contains(id.toOutKey())
|
override suspend fun contains(id: FromId): Boolean = to.contains(id.toOutKey())
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<FromId, FromRegistered> = to.getAll().asSequence().associate { (k, v) ->
|
||||||
|
k.toInnerKey() to v.toInnerValue()
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getById(id: FromId): FromRegistered? = to.getById(
|
override suspend fun getById(id: FromId): FromRegistered? = to.getById(
|
||||||
id.toOutKey()
|
id.toOutKey()
|
||||||
) ?.toInnerValue()
|
) ?.toInnerValue()
|
||||||
|
@@ -55,6 +55,10 @@ open class MapperReadKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
|||||||
key.toOutKey()
|
key.toOutKey()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<FromKey, FromValue> = to.getAll().map { (k, v) ->
|
||||||
|
k.toInnerKey() to v.toInnerValue()
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
override suspend fun count(): Long = to.count()
|
override suspend fun count(): Long = to.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,12 +1,19 @@
|
|||||||
package dev.inmo.micro_utils.repos.pagination
|
package dev.inmo.micro_utils.repos.pagination
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.toCoercedInt
|
||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
|
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
|
||||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||||
|
|
||||||
suspend inline fun <T, ID, REPO : ReadCRUDRepo<T, ID>> REPO.getAll(
|
suspend inline fun <T, ID, REPO : ReadCRUDRepo<T, ID>> REPO.getAll(
|
||||||
|
pagination: Pagination,
|
||||||
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
|
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
|
||||||
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<T>
|
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<T>
|
||||||
): List<T> = getAllWithNextPaging {
|
): List<T> = getAllWithNextPaging(pagination) {
|
||||||
methodCaller(this, it)
|
methodCaller(this, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend inline fun <T, ID, REPO : ReadCRUDRepo<T, ID>> REPO.getAll(
|
||||||
|
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
|
||||||
|
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<T>
|
||||||
|
): List<T> = getAll(maxPagePagination(), methodCaller)
|
||||||
|
@@ -1,15 +1,22 @@
|
|||||||
package dev.inmo.micro_utils.repos.pagination
|
package dev.inmo.micro_utils.repos.pagination
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.toCoercedInt
|
||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
|
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
|
||||||
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
|
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
|
||||||
|
|
||||||
suspend inline fun <Key, Value, REPO : ReadKeyValueRepo<Key, Value>> REPO.getAll(
|
suspend inline fun <Key, Value, REPO : ReadKeyValueRepo<Key, Value>> REPO.getAll(
|
||||||
|
pagination: Pagination,
|
||||||
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
|
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
|
||||||
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
|
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
|
||||||
): List<Pair<Key, Value>> = getAllWithNextPaging {
|
): List<Pair<Key, Value>> = getAllWithNextPaging(pagination) {
|
||||||
val result = methodCaller(it)
|
val result = methodCaller(it)
|
||||||
result.changeResultsUnchecked(
|
result.changeResultsUnchecked(
|
||||||
result.results.mapNotNull { it to (get(it) ?: return@mapNotNull null) }
|
result.results.mapNotNull { it to (get(it) ?: return@mapNotNull null) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend inline fun <Key, Value, REPO : ReadKeyValueRepo<Key, Value>> REPO.getAll(
|
||||||
|
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
|
||||||
|
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
|
||||||
|
): List<Pair<Key, Value>> = getAll(maxPagePagination(), methodCaller)
|
||||||
|
@@ -0,0 +1,11 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.pagination
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.toCoercedInt
|
||||||
|
import dev.inmo.micro_utils.pagination.FirstPagePagination
|
||||||
|
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||||
|
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
|
||||||
|
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
|
||||||
|
|
||||||
|
suspend inline fun ReadCRUDRepo<*, *>.maxPagePagination() = FirstPagePagination(count().toCoercedInt())
|
||||||
|
suspend inline fun ReadKeyValueRepo<*, *>.maxPagePagination() = FirstPagePagination(count().toCoercedInt())
|
||||||
|
suspend inline fun ReadKeyValuesRepo<*, *>.maxPagePagination() = FirstPagePagination(count().toCoercedInt())
|
@@ -1,13 +1,15 @@
|
|||||||
package dev.inmo.micro_utils.repos.pagination
|
package dev.inmo.micro_utils.repos.pagination
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.toCoercedInt
|
||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
|
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
|
||||||
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
|
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
|
||||||
|
|
||||||
suspend inline fun <Key, Value, REPO : ReadKeyValuesRepo<Key, Value>> REPO.getAll(
|
suspend inline fun <Key, Value, REPO : ReadKeyValuesRepo<Key, Value>> REPO.getAll(
|
||||||
|
pagination: Pagination,
|
||||||
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
|
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
|
||||||
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
|
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
|
||||||
): List<Pair<Key, List<Value>>> = getAllWithNextPaging {
|
): List<Pair<Key, List<Value>>> = getAllWithNextPaging(pagination) {
|
||||||
val keysResult = methodCaller(it)
|
val keysResult = methodCaller(it)
|
||||||
keysResult.changeResultsUnchecked(
|
keysResult.changeResultsUnchecked(
|
||||||
keysResult.results.map { k ->
|
keysResult.results.map { k ->
|
||||||
@@ -15,3 +17,8 @@ suspend inline fun <Key, Value, REPO : ReadKeyValuesRepo<Key, Value>> REPO.getAl
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend inline fun <Key, Value, REPO : ReadKeyValuesRepo<Key, Value>> REPO.getAll(
|
||||||
|
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
|
||||||
|
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
|
||||||
|
): List<Pair<Key, List<Value>>> = getAll(maxPagePagination(), methodCaller)
|
||||||
|
@@ -12,6 +12,8 @@ open class ReadCRUDFromKeyValueRepo<RegisteredType, IdType>(
|
|||||||
|
|
||||||
override suspend fun count(): Long = original.count()
|
override suspend fun count(): Long = original.count()
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<IdType, RegisteredType> = original.getAll()
|
||||||
|
|
||||||
override suspend fun getByPagination(pagination: Pagination): PaginationResult<RegisteredType> = original.values(pagination)
|
override suspend fun getByPagination(pagination: Pagination): PaginationResult<RegisteredType> = original.values(pagination)
|
||||||
|
|
||||||
override suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType> = original.keys(pagination)
|
override suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType> = original.keys(pagination)
|
||||||
|
@@ -11,6 +11,7 @@ import dev.inmo.micro_utils.pagination.utils.paginate
|
|||||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||||
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
|
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
|
||||||
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
|
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
|
||||||
|
import dev.inmo.micro_utils.repos.pagination.getAll
|
||||||
import dev.inmo.micro_utils.repos.transforms.kvs.ReadKeyValuesFromKeyValueRepo
|
import dev.inmo.micro_utils.repos.transforms.kvs.ReadKeyValuesFromKeyValueRepo
|
||||||
import kotlin.jvm.JvmInline
|
import kotlin.jvm.JvmInline
|
||||||
|
|
||||||
@@ -40,6 +41,8 @@ value class ReadKeyValueFromCRUDRepo<Key, Value>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<Key, Value> = original.getAll()
|
||||||
|
|
||||||
override suspend fun count(): Long = original.count()
|
override suspend fun count(): Long = original.count()
|
||||||
|
|
||||||
override suspend fun contains(key: Key): Boolean = original.contains(key)
|
override suspend fun contains(key: Key): Boolean = original.contains(key)
|
||||||
|
@@ -41,6 +41,8 @@ open class ReadKeyValueFromKeyValuesRepo<Key, Value>(
|
|||||||
return original.contains(key)
|
return original.contains(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<Key, List<Value>> = original.getAll()
|
||||||
|
|
||||||
override suspend fun keys(v: List<Value>, pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
|
override suspend fun keys(v: List<Value>, pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
|
||||||
val keys = mutableSetOf<Key>()
|
val keys = mutableSetOf<Key>()
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package dev.inmo.micro_utils.repos
|
package dev.inmo.micro_utils.repos
|
||||||
|
|
||||||
import dev.inmo.micro_utils.common.Warning
|
import dev.inmo.micro_utils.common.Warning
|
||||||
|
import dev.inmo.micro_utils.common.filename
|
||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
import dev.inmo.micro_utils.pagination.utils.reverse
|
import dev.inmo.micro_utils.pagination.utils.reverse
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
@@ -94,6 +95,8 @@ class FileReadKeyValueRepo(
|
|||||||
return File(folder, key).exists()
|
return File(folder, key).exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<String, File> = (folder.listFiles() ?.toList() ?: emptyList()).associateBy { it.filename.name }
|
||||||
|
|
||||||
override suspend fun count(): Long = folder.list() ?.size ?.toLong() ?: 0L
|
override suspend fun count(): Long = folder.list() ?.size ?.toLong() ?: 0L
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -32,6 +32,18 @@ abstract class AbstractAndroidCRUDRepo<ObjectType, IdType>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<IdType, ObjectType> = helper.readableTransaction {
|
||||||
|
select(
|
||||||
|
tableName,
|
||||||
|
null,
|
||||||
|
""
|
||||||
|
).use {
|
||||||
|
it.map {
|
||||||
|
it.toId() to it.toObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
override suspend fun getById(id: IdType): ObjectType? = helper.readableTransaction {
|
override suspend fun getById(id: IdType): ObjectType? = helper.readableTransaction {
|
||||||
select(
|
select(
|
||||||
tableName,
|
tableName,
|
||||||
|
@@ -104,6 +104,15 @@ class KeyValueStore<T : Any> internal constructor (
|
|||||||
|
|
||||||
override suspend fun contains(key: String): Boolean = sharedPreferences.contains(key)
|
override suspend fun contains(key: String): Boolean = sharedPreferences.contains(key)
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<String, T> {
|
||||||
|
val resultMap = mutableMapOf<String, T>()
|
||||||
|
for ((k, v) in sharedPreferences.all) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
resultMap[k] = (v as? T) ?: continue
|
||||||
|
}
|
||||||
|
return resultMap.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun count(): Long = sharedPreferences.all.size.toLong()
|
override suspend fun count(): Long = sharedPreferences.all.size.toLong()
|
||||||
|
|
||||||
override suspend fun set(toSet: Map<String, T>) {
|
override suspend fun set(toSet: Map<String, T>) {
|
||||||
|
@@ -45,5 +45,9 @@ abstract class AbstractExposedReadCRUDRepo<ObjectType, IdType>(
|
|||||||
select { selectById(id) }.limit(1).any()
|
select { selectById(id) }.limit(1).any()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<IdType, ObjectType> = transaction(database) {
|
||||||
|
selectAll().associate { it.asId to it.asObject }
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun count(): Long = transaction(db = database) { selectAll().count() }
|
override suspend fun count(): Long = transaction(db = database) { selectAll().count() }
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,6 @@ import dev.inmo.micro_utils.repos.ReadKeyValueRepo
|
|||||||
import dev.inmo.micro_utils.repos.exposed.*
|
import dev.inmo.micro_utils.repos.exposed.*
|
||||||
import dev.inmo.micro_utils.repos.exposed.utils.selectPaginated
|
import dev.inmo.micro_utils.repos.exposed.utils.selectPaginated
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
|
||||||
abstract class AbstractExposedReadKeyValueRepo<Key, Value>(
|
abstract class AbstractExposedReadKeyValueRepo<Key, Value>(
|
||||||
@@ -32,6 +31,8 @@ abstract class AbstractExposedReadKeyValueRepo<Key, Value>(
|
|||||||
select { selectById(key) }.limit(1).any()
|
select { selectById(key) }.limit(1).any()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<Key, Value> = transaction(database) { selectAll().associate { it.asKey to it.asObject } }
|
||||||
|
|
||||||
override suspend fun count(): Long = transaction(database) { selectAll().count() }
|
override suspend fun count(): Long = transaction(database) { selectAll().count() }
|
||||||
|
|
||||||
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = transaction(database) {
|
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = transaction(database) {
|
||||||
|
@@ -26,6 +26,8 @@ class ReadMapCRUDRepo<ObjectType, IdType>(
|
|||||||
|
|
||||||
override suspend fun contains(id: IdType): Boolean = map.containsKey(id)
|
override suspend fun contains(id: IdType): Boolean = map.containsKey(id)
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<IdType, ObjectType> = map.toMap()
|
||||||
|
|
||||||
override suspend fun count(): Long = map.size.toLong()
|
override suspend fun count(): Long = map.size.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -51,6 +51,8 @@ class ReadMapKeyValueRepo<Key, Value>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<Key, Value> = map.toMap()
|
||||||
|
|
||||||
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()
|
||||||
|
@@ -44,6 +44,7 @@ class KtorCRUDRepoClient<ObjectType, IdType, InputValue> (
|
|||||||
typeInfo<PaginationResult<ObjectType>>(),
|
typeInfo<PaginationResult<ObjectType>>(),
|
||||||
typeInfo<PaginationResult<IdType>>(),
|
typeInfo<PaginationResult<IdType>>(),
|
||||||
contentType,
|
contentType,
|
||||||
|
typeInfo<Map<IdType, ObjectType>>(),
|
||||||
idSerializer
|
idSerializer
|
||||||
),
|
),
|
||||||
KtorWriteCrudRepoClient<ObjectType, IdType, InputValue>(
|
KtorWriteCrudRepoClient<ObjectType, IdType, InputValue>(
|
||||||
|
@@ -5,6 +5,7 @@ import dev.inmo.micro_utils.pagination.*
|
|||||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.countRouting
|
import dev.inmo.micro_utils.repos.ktor.common.countRouting
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.getAllRoute
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
|
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.call.body
|
import io.ktor.client.call.body
|
||||||
@@ -21,6 +22,7 @@ class KtorReadCRUDRepoClient<ObjectType, IdType> (
|
|||||||
private val paginationObjectType: TypeInfo,
|
private val paginationObjectType: TypeInfo,
|
||||||
private val paginationIdType: TypeInfo,
|
private val paginationIdType: TypeInfo,
|
||||||
private val contentType: ContentType,
|
private val contentType: ContentType,
|
||||||
|
private val mapTypeInfo: TypeInfo,
|
||||||
private val idSerializer: suspend (IdType) -> String
|
private val idSerializer: suspend (IdType) -> String
|
||||||
) : ReadCRUDRepo<ObjectType, IdType> {
|
) : ReadCRUDRepo<ObjectType, IdType> {
|
||||||
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = httpClient.get(
|
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = httpClient.get(
|
||||||
@@ -58,6 +60,15 @@ class KtorReadCRUDRepoClient<ObjectType, IdType> (
|
|||||||
contentType(contentType)
|
contentType(contentType)
|
||||||
}.body()
|
}.body()
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<IdType, ObjectType> = httpClient.get(
|
||||||
|
buildStandardUrl(
|
||||||
|
baseUrl,
|
||||||
|
getAllRoute
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
contentType(contentType)
|
||||||
|
}.body(mapTypeInfo)
|
||||||
|
|
||||||
override suspend fun count(): Long = httpClient.get(
|
override suspend fun count(): Long = httpClient.get(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
@@ -80,6 +91,7 @@ inline fun <reified ObjectType, IdType> KtorReadCRUDRepoClient(
|
|||||||
typeInfo<PaginationResult<ObjectType>>(),
|
typeInfo<PaginationResult<ObjectType>>(),
|
||||||
typeInfo<PaginationResult<IdType>>(),
|
typeInfo<PaginationResult<IdType>>(),
|
||||||
contentType,
|
contentType,
|
||||||
|
typeInfo<Map<IdType, ObjectType>>(),
|
||||||
idSerializer
|
idSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -23,6 +23,7 @@ class KtorReadKeyValueRepoClient<Key, Value>(
|
|||||||
private val objectType: TypeInfo,
|
private val objectType: TypeInfo,
|
||||||
private val paginationResultObjectsTypeInfo: TypeInfo,
|
private val paginationResultObjectsTypeInfo: TypeInfo,
|
||||||
private val paginationResultIdsTypeInfo: TypeInfo,
|
private val paginationResultIdsTypeInfo: TypeInfo,
|
||||||
|
private val mapKeyValueTypeInfo: TypeInfo,
|
||||||
private val idSerializer: suspend (Key) -> String,
|
private val idSerializer: suspend (Key) -> String,
|
||||||
private val valueSerializer: suspend (Value) -> String
|
private val valueSerializer: suspend (Value) -> String
|
||||||
) : ReadKeyValueRepo<Key, Value> {
|
) : ReadKeyValueRepo<Key, Value> {
|
||||||
@@ -48,6 +49,15 @@ class KtorReadKeyValueRepoClient<Key, Value>(
|
|||||||
contentType(contentType)
|
contentType(contentType)
|
||||||
}.body()
|
}.body()
|
||||||
|
|
||||||
|
override suspend fun getAll(): Map<Key, Value> = httpClient.get(
|
||||||
|
buildStandardUrl(
|
||||||
|
baseUrl,
|
||||||
|
getAllRoute
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
contentType(contentType)
|
||||||
|
}.body(mapKeyValueTypeInfo)
|
||||||
|
|
||||||
override suspend fun values(
|
override suspend fun values(
|
||||||
pagination: Pagination,
|
pagination: Pagination,
|
||||||
reversed: Boolean
|
reversed: Boolean
|
||||||
@@ -103,6 +113,7 @@ inline fun <reified Key, reified Value> KtorReadKeyValueRepoClient(
|
|||||||
typeInfo<Value>(),
|
typeInfo<Value>(),
|
||||||
typeInfo<PaginationResult<Value>>(),
|
typeInfo<PaginationResult<Value>>(),
|
||||||
typeInfo<PaginationResult<Key>>(),
|
typeInfo<PaginationResult<Key>>(),
|
||||||
|
typeInfo<Map<Key, Value>>(),
|
||||||
idSerializer,
|
idSerializer,
|
||||||
valueSerializer
|
valueSerializer
|
||||||
)
|
)
|
||||||
|
@@ -0,0 +1,3 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.common
|
||||||
|
|
||||||
|
const val getAllRoute = "getAll"
|
@@ -83,6 +83,9 @@ class CRUDTests {
|
|||||||
assertEquals(map.size, 0)
|
assertEquals(map.size, 0)
|
||||||
assertEquals(map.size.toLong(), crudClient.count())
|
assertEquals(map.size.toLong(), crudClient.count())
|
||||||
assertEquals(0, crudClient.count())
|
assertEquals(0, crudClient.count())
|
||||||
|
|
||||||
|
assertEquals(map, crudClient.getAll())
|
||||||
|
|
||||||
server.stop()
|
server.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -133,6 +133,8 @@ class KVTests {
|
|||||||
crudClient.count()
|
crudClient.count()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assertEquals(map, crudClient.getAll())
|
||||||
|
|
||||||
server.stop()
|
server.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@ import dev.inmo.micro_utils.pagination.extractPagination
|
|||||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.countRouting
|
import dev.inmo.micro_utils.repos.ktor.common.countRouting
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.getAllRoute
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
|
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.call
|
import io.ktor.server.application.call
|
||||||
@@ -53,6 +54,10 @@ inline fun <reified ObjectType, reified IdType> Route.configureReadCRUDRepoRoute
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get(getAllRoute) {
|
||||||
|
call.respond(originalRepo.getAll())
|
||||||
|
}
|
||||||
|
|
||||||
get(countRouting) {
|
get(countRouting) {
|
||||||
call.respond(
|
call.respond(
|
||||||
originalRepo.count()
|
originalRepo.count()
|
||||||
|
@@ -70,6 +70,10 @@ inline fun <reified Key, reified Value> Route.configureReadKeyValueRepoRoutes (
|
|||||||
call.respond(originalRepo.contains(key))
|
call.respond(originalRepo.contains(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get(getAllRoute) {
|
||||||
|
call.respond(originalRepo.getAll())
|
||||||
|
}
|
||||||
|
|
||||||
get(countRoute) {
|
get(countRoute) {
|
||||||
call.respond(originalRepo.count())
|
call.respond(originalRepo.count())
|
||||||
}
|
}
|
||||||
|
7
serialization/mapper/build.gradle
Normal file
7
serialization/mapper/build.gradle
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
id "com.android.library"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppProjectWithSerializationPresetPath"
|
99
serialization/mapper/src/commonMain/kotlin/Extensions.kt
Normal file
99
serialization/mapper/src/commonMain/kotlin/Extensions.kt
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
package dev.inmo.micro_utils.serialization.mapper
|
||||||
|
|
||||||
|
import kotlinx.serialization.DeserializationStrategy
|
||||||
|
import kotlinx.serialization.InternalSerializationApi
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.SerializationStrategy
|
||||||
|
import kotlinx.serialization.serializer
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [MapperSerializationStrategy] to allow you to map [O] to [I] using [serialize] lambda during
|
||||||
|
* serialization process
|
||||||
|
*/
|
||||||
|
inline fun <reified I : Any, O> SerializationStrategy<I>.mapSerialization(
|
||||||
|
noinline serialize: (O) -> I
|
||||||
|
) = MapperSerializationStrategy(
|
||||||
|
this,
|
||||||
|
serialize
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [MapperDeserializationStrategy] to allow you to map [I] to [O] using [deserialize] lambda during
|
||||||
|
* deserialization process
|
||||||
|
*/
|
||||||
|
inline fun <reified I : Any, O> DeserializationStrategy<I>.mapDeserialization(
|
||||||
|
noinline deserialize: (I) -> O
|
||||||
|
) = MapperDeserializationStrategy(
|
||||||
|
this,
|
||||||
|
deserialize
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [MapperSerializer] to allow you to map [O] to [I] and vice verse using [serialize]/[deserialize] lambda during
|
||||||
|
* serialization/deserialization process
|
||||||
|
*/
|
||||||
|
inline fun <reified I : Any, O> KSerializer<I>.mapFullSerialization(
|
||||||
|
noinline serialize: (O) -> I,
|
||||||
|
noinline deserialize: (I) -> O
|
||||||
|
) = MapperSerializer(
|
||||||
|
this,
|
||||||
|
serialize,
|
||||||
|
deserialize
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [MapperSerializationStrategy] to allow you to map [O] to [I] using [serialize] lambda during
|
||||||
|
* serialization process
|
||||||
|
*/
|
||||||
|
@OptIn(InternalSerializationApi::class)
|
||||||
|
inline fun <reified I : Any, O> KClass<I>.mapSerialization(
|
||||||
|
serializer: SerializationStrategy<I> = serializer(),
|
||||||
|
noinline serialize: (O) -> I
|
||||||
|
) = serializer.mapSerialization(serialize)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [MapperDeserializationStrategy] to allow you to map [I] to [O] using [deserialize] lambda during
|
||||||
|
* deserialization process
|
||||||
|
*/
|
||||||
|
@OptIn(InternalSerializationApi::class)
|
||||||
|
inline fun <reified I : Any, O> KClass<I>.mapDeserialization(
|
||||||
|
serializer: DeserializationStrategy<I> = serializer(),
|
||||||
|
noinline deserialize: (I) -> O
|
||||||
|
) = serializer.mapDeserialization(deserialize)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [MapperSerializer] to allow you to map [O] to [I] and vice verse using [serialize]/[deserialize] lambda during
|
||||||
|
* serialization/deserialization process
|
||||||
|
*/
|
||||||
|
@OptIn(InternalSerializationApi::class)
|
||||||
|
inline fun <reified I : Any, O> KClass<I>.mapFullSerialization(
|
||||||
|
serializer: KSerializer<I> = serializer(),
|
||||||
|
noinline serialize: (O) -> I,
|
||||||
|
noinline deserialize: (I) -> O
|
||||||
|
) = serializer.mapFullSerialization(serialize, deserialize)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [MapperSerializationStrategy] to allow you to map [O] to [I] using [serialize] lambda during
|
||||||
|
* serialization process
|
||||||
|
*/
|
||||||
|
inline fun <reified I : Any, O> mappedSerializationStrategy(
|
||||||
|
noinline serialize: (O) -> I,
|
||||||
|
) = serializer<I>().mapSerialization(serialize)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [MapperDeserializationStrategy] to allow you to map [I] to [O] using [deserialize] lambda during
|
||||||
|
* deserialization process
|
||||||
|
*/
|
||||||
|
inline fun <reified I : Any, O> mappedDeserializationStrategy(
|
||||||
|
noinline deserialize: (I) -> O
|
||||||
|
) = serializer<I>().mapDeserialization(deserialize)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create [MapperSerializer] to allow you to map [O] to [I] and vice verse using [serialize]/[deserialize] lambda during
|
||||||
|
* serialization/deserialization process
|
||||||
|
*/
|
||||||
|
inline fun <reified I : Any, O> mappedSerializer(
|
||||||
|
noinline serialize: (O) -> I,
|
||||||
|
noinline deserialize: (I) -> O
|
||||||
|
) = serializer<I>().mapFullSerialization(serialize, deserialize)
|
@@ -0,0 +1,26 @@
|
|||||||
|
package dev.inmo.micro_utils.serialization.mapper
|
||||||
|
|
||||||
|
import kotlinx.serialization.DeserializationStrategy
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.SerializationStrategy
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this serializer when you have deserializable type [I] and want to map it to some [O] in process of
|
||||||
|
* deserialization
|
||||||
|
*
|
||||||
|
* @param base Serializer for [I]
|
||||||
|
* @param deserialize Will be used in [deserialize] method to convert deserialized by [base] [I] to [O]
|
||||||
|
*/
|
||||||
|
open class MapperDeserializationStrategy<I, O>(
|
||||||
|
private val base: DeserializationStrategy<I>,
|
||||||
|
private val deserialize: (I) -> O
|
||||||
|
) : DeserializationStrategy<O> {
|
||||||
|
override val descriptor: SerialDescriptor = base.descriptor
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): O {
|
||||||
|
return deserialize(base.deserialize(decoder))
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
package dev.inmo.micro_utils.serialization.mapper
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.SerializationStrategy
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this serializer when you have serializable type [I] and want to map it to some [O] in process of
|
||||||
|
* serialization
|
||||||
|
*
|
||||||
|
* @param base Serializer for [I]
|
||||||
|
* @param serialize Will be used in [serialize] method to convert incoming [O] to [I] and serialize with [base]
|
||||||
|
*/
|
||||||
|
open class MapperSerializationStrategy<I, O>(
|
||||||
|
private val base: SerializationStrategy<I>,
|
||||||
|
private val serialize: (O) -> I
|
||||||
|
) : SerializationStrategy<O> {
|
||||||
|
override val descriptor: SerialDescriptor = base.descriptor
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: O) {
|
||||||
|
base.serialize(encoder, serialize(value))
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,30 @@
|
|||||||
|
package dev.inmo.micro_utils.serialization.mapper
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this serializer when you have serializable type [I] and want to map it to some [O] in process of
|
||||||
|
* serialization/deserialization
|
||||||
|
*
|
||||||
|
* @param base Serializer for [I]
|
||||||
|
* @param serialize Will be used in [serialize] method to convert incoming [O] to [I] and serialize with [base]
|
||||||
|
* @param deserialize Will be used in [deserialize] method to convert deserialized by [base] [I] to [O]
|
||||||
|
*/
|
||||||
|
open class MapperSerializer<I, O>(
|
||||||
|
private val base: KSerializer<I>,
|
||||||
|
private val serialize: (O) -> I,
|
||||||
|
private val deserialize: (I) -> O
|
||||||
|
) : KSerializer<O> {
|
||||||
|
override val descriptor: SerialDescriptor = base.descriptor
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): O {
|
||||||
|
return deserialize(base.deserialize(decoder))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: O) {
|
||||||
|
base.serialize(encoder, serialize(value))
|
||||||
|
}
|
||||||
|
}
|
1
serialization/mapper/src/main/AndroidManifest.xml
Normal file
1
serialization/mapper/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.micro_utils.serialization.mapper"/>
|
@@ -37,6 +37,7 @@ String[] includes = [
|
|||||||
":serialization:base64",
|
":serialization:base64",
|
||||||
":serialization:encapsulator",
|
":serialization:encapsulator",
|
||||||
":serialization:typed_serializer",
|
":serialization:typed_serializer",
|
||||||
|
":serialization:mapper",
|
||||||
":startup:plugin",
|
":startup:plugin",
|
||||||
":startup:launcher",
|
":startup:launcher",
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@ plugins {
|
|||||||
id "application"
|
id "application"
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppJsAndJavaProjectPresetPath"
|
apply from: "$mppJvmJsLinuxMingwProjectPresetPath"
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
@@ -3,7 +3,7 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppJsAndJavaProjectPresetPath"
|
apply from: "$mppJvmJsLinuxMingwProjectPresetPath"
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
sourceSets {
|
sourceSets {
|
||||||
@@ -21,5 +21,15 @@ kotlin {
|
|||||||
api libs.uuid
|
api libs.uuid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
linuxX64Main {
|
||||||
|
dependencies {
|
||||||
|
api libs.uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mingwX64Main {
|
||||||
|
dependencies {
|
||||||
|
api libs.uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,36 @@
|
|||||||
|
package dev.inmo.micro_utils.startup.plugin
|
||||||
|
|
||||||
|
import com.benasher44.uuid.uuid4
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
actual object StartPluginSerializer : KSerializer<StartPlugin> {
|
||||||
|
private val registeredPlugins = mutableMapOf<String, StartPlugin>()
|
||||||
|
private val registeredPluginsByPlugin = mutableMapOf<StartPlugin, String>()
|
||||||
|
override val descriptor: SerialDescriptor = String.serializer().descriptor
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): StartPlugin {
|
||||||
|
val name = decoder.decodeString()
|
||||||
|
return registeredPlugins[name] ?: error("Unable to find startup plugin for $name")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: StartPlugin) {
|
||||||
|
val name = registeredPluginsByPlugin[value] ?: uuid4().toString().also {
|
||||||
|
registeredPlugins[it] = value
|
||||||
|
registeredPluginsByPlugin[value] = it
|
||||||
|
}
|
||||||
|
encoder.encodeString(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register plugin inside of this [KSerializer]. Since plugin has been registered, you may use its [name] in any
|
||||||
|
* serialized [dev.inmo.micro_utils.startup.launcher.Config] to retrieve [plugin] you passed here
|
||||||
|
*/
|
||||||
|
fun registerPlugin(name: String, plugin: StartPlugin) {
|
||||||
|
registeredPlugins[name] = plugin
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,36 @@
|
|||||||
|
package dev.inmo.micro_utils.startup.plugin
|
||||||
|
|
||||||
|
import com.benasher44.uuid.uuid4
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
actual object StartPluginSerializer : KSerializer<StartPlugin> {
|
||||||
|
private val registeredPlugins = mutableMapOf<String, StartPlugin>()
|
||||||
|
private val registeredPluginsByPlugin = mutableMapOf<StartPlugin, String>()
|
||||||
|
override val descriptor: SerialDescriptor = String.serializer().descriptor
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): StartPlugin {
|
||||||
|
val name = decoder.decodeString()
|
||||||
|
return registeredPlugins[name] ?: error("Unable to find startup plugin for $name")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: StartPlugin) {
|
||||||
|
val name = registeredPluginsByPlugin[value] ?: uuid4().toString().also {
|
||||||
|
registeredPlugins[it] = value
|
||||||
|
registeredPluginsByPlugin[value] = it
|
||||||
|
}
|
||||||
|
encoder.encodeString(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register plugin inside of this [KSerializer]. Since plugin has been registered, you may use its [name] in any
|
||||||
|
* serialized [dev.inmo.micro_utils.startup.launcher.Config] to retrieve [plugin] you passed here
|
||||||
|
*/
|
||||||
|
fun registerPlugin(name: String, plugin: StartPlugin) {
|
||||||
|
registeredPlugins[name] = plugin
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user