mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-19 07:19:22 +00:00
Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
c443bf4fa0 | |||
a6982de822 | |||
4f1a663e75 | |||
dab262d626 | |||
87a3f61ca6 | |||
506e937a68 | |||
5a037c76dd | |||
313f622f7e | |||
6cba1fe1a2 | |||
fd2d0e80b7 | |||
96ab2e8aca | |||
0202988cae | |||
d619d59947 | |||
85b3e48d18 | |||
7a9b7d98a1 | |||
b212acfcaf | |||
3a45e5dc70 | |||
73190518d5 | |||
03f78180dc | |||
1c0b8cf842 | |||
a1624ea2a9 | |||
23a050cf1e |
48
CHANGELOG.md
48
CHANGELOG.md
@@ -1,5 +1,53 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.9.8
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Exposed`: `0.37.2` -> `0.37.3`
|
||||||
|
* `Klock`: `2.4.13` -> `2.5.1`
|
||||||
|
* `AppCompat`: `1.4.0` -> `1.4.1`
|
||||||
|
|
||||||
|
## 0.9.7
|
||||||
|
|
||||||
|
* `Repos`:
|
||||||
|
* `Exposed`:
|
||||||
|
* Fix in `ExposedOneToManyKeyValueRepo` - now it will not use `insertIgnore`
|
||||||
|
* `Ktor`:
|
||||||
|
* `Server`:
|
||||||
|
* `Route#includeWebsocketHandling` now will check that `WebSockets` feature and install it if not
|
||||||
|
|
||||||
|
## 0.9.6
|
||||||
|
|
||||||
|
* `Repos`:
|
||||||
|
* `Exposed`:
|
||||||
|
* Fix in `ExposedOneToManyKeyValueRepo` - now it will not use `deleteIgnoreWhere`
|
||||||
|
|
||||||
|
## 0.9.5
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Klock`: `2.4.12` -> `2.4.13`
|
||||||
|
|
||||||
|
## 0.9.4
|
||||||
|
|
||||||
|
* `Pagination`:
|
||||||
|
* `Common`:
|
||||||
|
* Add several `optionallyReverse` functions
|
||||||
|
* `Common`:
|
||||||
|
* Changes in `Either`:
|
||||||
|
* Now `Either` uses `optionalT1` and `optionalT2` as main properties
|
||||||
|
* `Either#t1` and `Either#t2` are deprecated
|
||||||
|
* New extensions `Either#mapOnFirst` and `Either#mapOnSecond`
|
||||||
|
|
||||||
|
## 0.9.3
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `UUID`: `0.3.1` -> `0.4.0`
|
||||||
|
|
||||||
|
## 0.9.2
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Klock`: `2.4.10` -> `2.4.12`
|
||||||
|
|
||||||
## 0.9.1
|
## 0.9.1
|
||||||
|
|
||||||
* `Repos`:
|
* `Repos`:
|
||||||
|
@@ -6,7 +6,7 @@ import kotlinx.serialization.descriptors.*
|
|||||||
import kotlinx.serialization.encoding.*
|
import kotlinx.serialization.encoding.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Realization of this interface will contains at least one not null - [t1] or [t2]
|
* Realization of this interface will contains at least one not null - [optionalT1] or [optionalT2]
|
||||||
*
|
*
|
||||||
* @see EitherFirst
|
* @see EitherFirst
|
||||||
* @see EitherSecond
|
* @see EitherSecond
|
||||||
@@ -14,11 +14,19 @@ import kotlinx.serialization.encoding.*
|
|||||||
* @see Either.Companion.second
|
* @see Either.Companion.second
|
||||||
* @see Either.onFirst
|
* @see Either.onFirst
|
||||||
* @see Either.onSecond
|
* @see Either.onSecond
|
||||||
|
* @see Either.mapOnFirst
|
||||||
|
* @see Either.mapOnSecond
|
||||||
*/
|
*/
|
||||||
@Serializable(EitherSerializer::class)
|
@Serializable(EitherSerializer::class)
|
||||||
sealed interface Either<T1, T2> {
|
sealed interface Either<T1, T2> {
|
||||||
|
val optionalT1: Optional<T1>
|
||||||
|
val optionalT2: Optional<T2>
|
||||||
|
@Deprecated("Use optionalT1 instead", ReplaceWith("optionalT1"))
|
||||||
val t1: T1?
|
val t1: T1?
|
||||||
|
get() = optionalT1.dataOrNull()
|
||||||
|
@Deprecated("Use optionalT2 instead", ReplaceWith("optionalT2"))
|
||||||
val t2: T2?
|
val t2: T2?
|
||||||
|
get() = optionalT2.dataOrNull()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun <T1, T2> serializer(
|
fun <T1, T2> serializer(
|
||||||
@@ -93,25 +101,25 @@ class EitherSerializer<T1, T2>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This type [Either] will always have not nullable [t1]
|
* This type [Either] will always have not nullable [optionalT1]
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class EitherFirst<T1, T2>(
|
data class EitherFirst<T1, T2>(
|
||||||
override val t1: T1
|
override val t1: T1
|
||||||
) : Either<T1, T2> {
|
) : Either<T1, T2> {
|
||||||
override val t2: T2?
|
override val optionalT1: Optional<T1> = t1.optional
|
||||||
get() = null
|
override val optionalT2: Optional<T2> = Optional.absent()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This type [Either] will always have not nullable [t2]
|
* This type [Either] will always have not nullable [optionalT2]
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class EitherSecond<T1, T2>(
|
data class EitherSecond<T1, T2>(
|
||||||
override val t2: T2
|
override val t2: T2
|
||||||
) : Either<T1, T2> {
|
) : Either<T1, T2> {
|
||||||
override val t1: T1?
|
override val optionalT1: Optional<T1> = Optional.absent()
|
||||||
get() = null
|
override val optionalT2: Optional<T2> = t2.optional
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,23 +132,35 @@ inline fun <T1, T2> Either.Companion.first(t1: T1): Either<T1, T2> = EitherFirst
|
|||||||
inline fun <T1, T2> Either.Companion.second(t2: T2): Either<T1, T2> = EitherSecond(t2)
|
inline fun <T1, T2> Either.Companion.second(t2: T2): Either<T1, T2> = EitherSecond(t2)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will call [block] in case when [Either.t1] of [this] is not null
|
* Will call [block] in case when [this] is [EitherFirst]
|
||||||
*/
|
*/
|
||||||
inline fun <T1, T2, E : Either<T1, T2>> E.onFirst(block: (T1) -> Unit): E {
|
inline fun <T1, T2, E : Either<T1, T2>> E.onFirst(block: (T1) -> Unit): E {
|
||||||
val t1 = t1
|
optionalT1.onPresented(block)
|
||||||
t1 ?.let(block)
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will call [block] in case when [Either.t2] of [this] is not null
|
* Will call [block] in case when [this] is [EitherSecond]
|
||||||
*/
|
*/
|
||||||
inline fun <T1, T2, E : Either<T1, T2>> E.onSecond(block: (T2) -> Unit): E {
|
inline fun <T1, T2, E : Either<T1, T2>> E.onSecond(block: (T2) -> Unit): E {
|
||||||
val t2 = t2
|
optionalT2.onPresented(block)
|
||||||
t2 ?.let(block)
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Result of [block] if [this] is [EitherFirst]
|
||||||
|
*/
|
||||||
|
inline fun <T1, R> Either<T1, *>.mapOnFirst(block: (T1) -> R): R? {
|
||||||
|
return optionalT1.mapOnPresented(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Result of [block] if [this] is [EitherSecond]
|
||||||
|
*/
|
||||||
|
inline fun <T2, R> Either<*, T2>.mapOnSecond(block: (T2) -> R): R? {
|
||||||
|
return optionalT2.mapOnPresented(block)
|
||||||
|
}
|
||||||
|
|
||||||
inline fun <reified T1, reified T2> Any.either() = when (this) {
|
inline fun <reified T1, reified T2> Any.either() = when (this) {
|
||||||
is T1 -> Either.first<T1, T2>(this)
|
is T1 -> Either.first<T1, T2>(this)
|
||||||
is T2 -> Either.second<T1, T2>(this)
|
is T2 -> Either.second<T1, T2>(this)
|
||||||
|
@@ -10,21 +10,21 @@ org.gradle.jvmargs=-Xmx2g
|
|||||||
kotlin_version=1.6.10
|
kotlin_version=1.6.10
|
||||||
kotlin_coroutines_version=1.6.0
|
kotlin_coroutines_version=1.6.0
|
||||||
kotlin_serialisation_core_version=1.3.2
|
kotlin_serialisation_core_version=1.3.2
|
||||||
kotlin_exposed_version=0.37.2
|
kotlin_exposed_version=0.37.3
|
||||||
|
|
||||||
ktor_version=1.6.7
|
ktor_version=1.6.7
|
||||||
|
|
||||||
klockVersion=2.4.10
|
klockVersion=2.5.1
|
||||||
|
|
||||||
github_release_plugin_version=2.2.12
|
github_release_plugin_version=2.2.12
|
||||||
|
|
||||||
uuidVersion=0.3.1
|
uuidVersion=0.4.0
|
||||||
|
|
||||||
# ANDROID
|
# ANDROID
|
||||||
|
|
||||||
core_ktx_version=1.7.0
|
core_ktx_version=1.7.0
|
||||||
androidx_recycler_version=1.2.1
|
androidx_recycler_version=1.2.1
|
||||||
appcompat_version=1.4.0
|
appcompat_version=1.4.1
|
||||||
|
|
||||||
android_minSdkVersion=19
|
android_minSdkVersion=19
|
||||||
android_compileSdkVersion=32
|
android_compileSdkVersion=32
|
||||||
@@ -40,10 +40,10 @@ crypto_js_version=4.1.1
|
|||||||
|
|
||||||
# Dokka
|
# Dokka
|
||||||
|
|
||||||
dokka_version=1.6.0
|
dokka_version=1.6.10
|
||||||
|
|
||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.9.1
|
version=0.9.8
|
||||||
android_code_version=91
|
android_code_version=98
|
||||||
|
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-7.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@@ -2,25 +2,23 @@ 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.featureOrNull
|
||||||
|
import io.ktor.application.install
|
||||||
import io.ktor.http.cio.websocket.*
|
import io.ktor.http.cio.websocket.*
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
|
import io.ktor.routing.application
|
||||||
import io.ktor.websocket.webSocket
|
import io.ktor.websocket.webSocket
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.serialization.SerializationStrategy
|
import kotlinx.serialization.SerializationStrategy
|
||||||
|
|
||||||
private suspend fun DefaultWebSocketSession.checkReceivedAndCloseIfExists() {
|
|
||||||
if (incoming.tryReceive() != null) {
|
|
||||||
close()
|
|
||||||
throw CorrectCloseException
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> Route.includeWebsocketHandling(
|
fun <T> Route.includeWebsocketHandling(
|
||||||
suburl: String,
|
suburl: String,
|
||||||
flow: Flow<T>,
|
flow: Flow<T>,
|
||||||
converter: (T) -> StandardKtorSerialInputData
|
converter: (T) -> StandardKtorSerialInputData
|
||||||
) {
|
) {
|
||||||
|
application.apply {
|
||||||
|
featureOrNull(io.ktor.websocket.WebSockets) ?: install(io.ktor.websocket.WebSockets)
|
||||||
|
}
|
||||||
webSocket(suburl) {
|
webSocket(suburl) {
|
||||||
safely {
|
safely {
|
||||||
flow.collect {
|
flow.collect {
|
||||||
|
@@ -38,3 +38,31 @@ fun <T> Set<T>.paginate(with: Pagination): PaginationResult<T> {
|
|||||||
size.toLong()
|
size.toLong()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> Iterable<T>.optionallyReverse(reverse: Boolean): Iterable<T> = when (this) {
|
||||||
|
is List<T> -> optionallyReverse(reverse)
|
||||||
|
is Set<T> -> optionallyReverse(reverse)
|
||||||
|
else -> if (reverse) {
|
||||||
|
reversed()
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun <T> List<T>.optionallyReverse(reverse: Boolean): List<T> = if (reverse) {
|
||||||
|
reversed()
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
fun <T> Set<T>.optionallyReverse(reverse: Boolean): Set<T> = if (reverse) {
|
||||||
|
reversed().toSet()
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> Array<T>.optionallyReverse(reverse: Boolean) = if (reverse) {
|
||||||
|
Array(size) {
|
||||||
|
get(lastIndex - it)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
@@ -26,3 +26,15 @@ fun Pagination.reverse(datasetSize: Long): SimplePagination {
|
|||||||
* Shortcut for [reverse]
|
* Shortcut for [reverse]
|
||||||
*/
|
*/
|
||||||
fun Pagination.reverse(objectsCount: Int) = reverse(objectsCount.toLong())
|
fun Pagination.reverse(objectsCount: Int) = reverse(objectsCount.toLong())
|
||||||
|
|
||||||
|
fun Pagination.optionallyReverse(objectsCount: Int, reverse: Boolean) = if (reverse) {
|
||||||
|
reverse(objectsCount)
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Pagination.optionallyReverse(objectsCount: Long, reverse: Boolean) = if (reverse) {
|
||||||
|
reverse(objectsCount)
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
@@ -35,10 +35,15 @@ open class ExposedOneToManyKeyValueRepo<Key, Value>(
|
|||||||
if (select { keyColumn.eq(k).and(valueColumn.eq(v)) }.limit(1).count() > 0) {
|
if (select { keyColumn.eq(k).and(valueColumn.eq(v)) }.limit(1).count() > 0) {
|
||||||
return@mapNotNull null
|
return@mapNotNull null
|
||||||
}
|
}
|
||||||
insertIgnore {
|
val insertResult = insert {
|
||||||
it[keyColumn] = k
|
it[keyColumn] = k
|
||||||
it[valueColumn] = v
|
it[valueColumn] = v
|
||||||
}.getOrNull(keyColumn) ?.let { k to v }
|
}
|
||||||
|
if (insertResult.insertedCount > 0) {
|
||||||
|
k to v
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
}.forEach { _onNewValue.emit(it) }
|
}.forEach { _onNewValue.emit(it) }
|
||||||
@@ -48,7 +53,7 @@ open class ExposedOneToManyKeyValueRepo<Key, Value>(
|
|||||||
transaction(database) {
|
transaction(database) {
|
||||||
toRemove.keys.flatMap { k ->
|
toRemove.keys.flatMap { k ->
|
||||||
toRemove[k] ?.mapNotNull { v ->
|
toRemove[k] ?.mapNotNull { v ->
|
||||||
if (deleteIgnoreWhere { keyColumn.eq(k).and(valueColumn.eq(v)) } > 0 ) {
|
if (deleteWhere { keyColumn.eq(k).and(valueColumn.eq(v)) } > 0 ) {
|
||||||
k to v
|
k to v
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
Reference in New Issue
Block a user