mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2026-04-12 20:42:25 +00:00
Compare commits
18 Commits
74563bbac9
...
0.24.7
| Author | SHA1 | Date | |
|---|---|---|---|
| 260399e965 | |||
| de72843b8e | |||
| b589142d9f | |||
| f479c85869 | |||
| 26992c039a | |||
| ef50e1a24f | |||
| 2f201670d2 | |||
| 90c80573a0 | |||
| 059519cdca | |||
| 55647e2e2f | |||
| 1802be68ef | |||
| aa79496a36 | |||
| 4bfa4c32aa | |||
| d8ca29eab1 | |||
| f7a9f2e13d | |||
| af286d3d53 | |||
| 9a20e8155e | |||
| b81af7e1c8 |
23
CHANGELOG.md
23
CHANGELOG.md
@@ -1,7 +1,30 @@
|
||||
# Changelog
|
||||
|
||||
## 0.24.7
|
||||
|
||||
* `Versions`:
|
||||
* `SQLite`: `3.49.0.0` -> `3.49.1.0`
|
||||
* `Common`:
|
||||
* Add `retryOnFailure` utility for simple retries code writing
|
||||
* `Repos`:
|
||||
* `Cache`:
|
||||
* Fix of `FullKeyValueCacheRepo` fields usage
|
||||
* `Exposed`:
|
||||
* `AbstractExposedKeyValuesRepo` will produce `onValueRemoved` event on `set` if some data has been removed
|
||||
|
||||
## 0.24.6
|
||||
|
||||
* `Versions`:
|
||||
* `KSLog`: `1.4.0` -> `1.4.1`
|
||||
* `Exposed`: `0.58.0` -> `0.59.0`
|
||||
* `SQLite`: `3.48.0.0` -> `3.49.0.0`
|
||||
* `AndroidFragment`: `1.8.5` -> `1.8.6`
|
||||
* `Coroutines`:
|
||||
* Safely functions has been replaced with `Logging` variations (resolve of [#541](https://github.com/InsanusMokrassar/MicroUtils/issues/541))
|
||||
* `KSP`:
|
||||
* `Variations`:
|
||||
* Module has been created
|
||||
|
||||
## 0.24.5
|
||||
|
||||
* `Versions`:
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
/**
|
||||
* Will try to execute [action] and, if any exception will happen, execution will be retried.
|
||||
* This process will happen at most [count] times. There is no any limits on [count] value, but [action] will run at
|
||||
* least once and [retryOnFailure] will return its result if it is successful
|
||||
*/
|
||||
inline fun <T> retryOnFailure(count: Int, action: () -> T): T {
|
||||
var triesCount = 0
|
||||
while (true) {
|
||||
val result = runCatching {
|
||||
action()
|
||||
}.onFailure {
|
||||
triesCount++
|
||||
|
||||
if (triesCount >= count) {
|
||||
throw it
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isSuccess) return result.getOrThrow()
|
||||
}
|
||||
error("Unreachable code: retry must throw latest exception if error happen or success value if not")
|
||||
}
|
||||
@@ -11,6 +11,7 @@ kotlin {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api libs.kt.coroutines
|
||||
api libs.kslog
|
||||
}
|
||||
}
|
||||
jsMain {
|
||||
|
||||
@@ -41,4 +41,4 @@ class ContextSafelyExceptionHandler(
|
||||
) : CoroutineContext.Element {
|
||||
override val key: CoroutineContext.Key<*>
|
||||
get() = ContextSafelyExceptionHandlerKey
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import dev.inmo.kslog.common.KSLog
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@@ -16,6 +17,45 @@ inline fun <T> Flow<T>.subscribe(scope: CoroutineScope, noinline block: suspend
|
||||
* Use [subscribe], but all [block]s will be called inside of [safely] function.
|
||||
* Use [onException] to set up your reaction for [Throwable]s
|
||||
*/
|
||||
inline fun <T> Flow<T>.subscribeLogging(
|
||||
scope: CoroutineScope,
|
||||
noinline errorMessageBuilder: T.(Throwable) -> Any = { "Something web wrong" },
|
||||
logger: KSLog = KSLog,
|
||||
noinline block: suspend (T) -> Unit
|
||||
) = subscribe(scope) {
|
||||
it.runCatchingLogging(
|
||||
errorMessageBuilder,
|
||||
logger
|
||||
) {
|
||||
block(it)
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Use [subscribeSafelyWithoutExceptions], but all exceptions will be passed to [defaultSafelyExceptionHandler]
|
||||
*/
|
||||
inline fun <T> Flow<T>.subscribeLoggingDropExceptions(
|
||||
scope: CoroutineScope,
|
||||
noinline errorMessageBuilder: T.(Throwable) -> Any = { "Something web wrong" },
|
||||
logger: KSLog = KSLog,
|
||||
noinline block: suspend (T) -> Unit
|
||||
) = subscribe(scope) {
|
||||
it.runCatchingLogging(
|
||||
errorMessageBuilder,
|
||||
logger
|
||||
) {
|
||||
block(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use [subscribe], but all [block]s will be called inside of [safely] function.
|
||||
* Use [onException] to set up your reaction for [Throwable]s
|
||||
*/
|
||||
@Deprecated(
|
||||
"Will be removed soon due to replacement by subscribeLogging",
|
||||
ReplaceWith("this.subscribeLogging(scope = scope, block = block)")
|
||||
)
|
||||
inline fun <T> Flow<T>.subscribeSafely(
|
||||
scope: CoroutineScope,
|
||||
noinline onException: ExceptionHandler<Unit> = defaultSafelyExceptionHandler,
|
||||
@@ -29,6 +69,10 @@ inline fun <T> Flow<T>.subscribeSafely(
|
||||
/**
|
||||
* Use [subscribeSafelyWithoutExceptions], but all exceptions will be passed to [defaultSafelyExceptionHandler]
|
||||
*/
|
||||
@Deprecated(
|
||||
"Will be removed soon due to replacement by subscribeLoggingDropExceptions",
|
||||
ReplaceWith("this.subscribeLoggingDropExceptions(scope = scope, block = block)")
|
||||
)
|
||||
inline fun <T> Flow<T>.subscribeSafelyWithoutExceptions(
|
||||
scope: CoroutineScope,
|
||||
noinline onException: ExceptionHandler<T?> = defaultSafelyWithoutExceptionHandlerWithNull,
|
||||
@@ -42,6 +86,10 @@ inline fun <T> Flow<T>.subscribeSafelyWithoutExceptions(
|
||||
/**
|
||||
* Use [subscribeSafelyWithoutExceptions], but all exceptions inside of [safely] will be skipped
|
||||
*/
|
||||
@Deprecated(
|
||||
"Will be removed soon due to replacement by subscribeLoggingDropExceptions",
|
||||
ReplaceWith("this.subscribeLoggingDropExceptions(scope = scope, block = block)")
|
||||
)
|
||||
inline fun <T> Flow<T>.subscribeSafelySkippingExceptions(
|
||||
scope: CoroutineScope,
|
||||
noinline block: suspend (T) -> Unit
|
||||
|
||||
@@ -15,7 +15,7 @@ private class SubscribeAsyncReceiver<T>(
|
||||
get() = dataChannel
|
||||
|
||||
init {
|
||||
scope.launchSafelyWithoutExceptions {
|
||||
scope.launchLoggingDropExceptions {
|
||||
for (data in dataChannel) {
|
||||
output(data)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ import kotlin.coroutines.coroutineContext
|
||||
*
|
||||
* @return [Result] with result of [block] if no exceptions or [Result] from [onException] execution
|
||||
*/
|
||||
@Deprecated(
|
||||
"This function become redundant since coroutines correctly handling throwing exceptions",
|
||||
replaceWith = ReplaceWith("runCatching(block).replaceIfFailure { onException(it) }")
|
||||
)
|
||||
suspend inline fun <T> runCatchingSafely(
|
||||
onException: ExceptionHandler<T>,
|
||||
block: suspend () -> T
|
||||
@@ -29,6 +33,10 @@ suspend inline fun <T> runCatchingSafely(
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"This function become redundant since coroutines correctly handling throwing exceptions",
|
||||
replaceWith = ReplaceWith("runCatching(block).replaceIfFailure { onException(it) }")
|
||||
)
|
||||
suspend inline fun <T, R> R.runCatchingSafely(
|
||||
onException: ExceptionHandler<T>,
|
||||
block: suspend R.() -> T
|
||||
@@ -39,10 +47,18 @@ suspend inline fun <T, R> R.runCatchingSafely(
|
||||
/**
|
||||
* Launching [runCatchingSafely] with [defaultSafelyExceptionHandler] as `onException` parameter
|
||||
*/
|
||||
@Deprecated(
|
||||
"This function become redundant since coroutines correctly handling throwing exceptions",
|
||||
replaceWith = ReplaceWith("runCatching(block).replaceIfFailure { defaultSafelyExceptionHandler(it) }")
|
||||
)
|
||||
suspend inline fun <T> runCatchingSafely(
|
||||
block: suspend () -> T
|
||||
): Result<T> = runCatchingSafely(defaultSafelyExceptionHandler, block)
|
||||
|
||||
@Deprecated(
|
||||
"This function become redundant since coroutines correctly handling throwing exceptions",
|
||||
replaceWith = ReplaceWith("runCatching(block).replaceIfFailure { defaultSafelyExceptionHandler(it) }")
|
||||
)
|
||||
suspend inline fun <T, R> R.runCatchingSafely(
|
||||
block: suspend R.() -> T
|
||||
): Result<T> = runCatchingSafely<T> {
|
||||
@@ -73,6 +89,9 @@ suspend fun contextSafelyExceptionHandler() = coroutineContext[ContextSafelyExce
|
||||
* After all, will be called [withContext] method with created [ContextSafelyExceptionHandler] and block which will call
|
||||
* [safely] method with [safelyExceptionHandler] as onException parameter and [block] as execution block
|
||||
*/
|
||||
@Deprecated(
|
||||
"This function become redundant since coroutines correctly handling throwing exceptions",
|
||||
)
|
||||
suspend fun <T> safelyWithContextExceptionHandler(
|
||||
contextExceptionHandler: ExceptionHandler<Unit>,
|
||||
safelyExceptionHandler: ExceptionHandler<T> = defaultSafelyExceptionHandler,
|
||||
@@ -94,6 +113,10 @@ suspend fun <T> safelyWithContextExceptionHandler(
|
||||
*
|
||||
* @see runCatchingSafely
|
||||
*/
|
||||
@Deprecated(
|
||||
"This function become redundant since coroutines correctly handling throwing exceptions",
|
||||
replaceWith = ReplaceWith("runCatching(block).replaceIfFailure { onException(it) }.getOrThrow()")
|
||||
)
|
||||
suspend inline fun <T> safely(
|
||||
onException: ExceptionHandler<T>,
|
||||
block: suspend () -> T
|
||||
@@ -104,9 +127,17 @@ suspend inline fun <T> safely(
|
||||
*
|
||||
* @see runCatchingSafely
|
||||
*/
|
||||
@Deprecated(
|
||||
"This function become redundant since coroutines correctly handling throwing exceptions",
|
||||
replaceWith = ReplaceWith("runCatching(block).replaceIfFailure { defaultSafelyExceptionHandler(it) }.getOrThrow()")
|
||||
)
|
||||
suspend inline fun <T> safely(
|
||||
block: suspend () -> T
|
||||
): T = safely(defaultSafelyExceptionHandler, block)
|
||||
@Deprecated(
|
||||
"This function become redundant since coroutines correctly handling throwing exceptions",
|
||||
replaceWith = ReplaceWith("runCatching(block).replaceIfFailure { defaultSafelyExceptionHandler(it) }.getOrThrow()")
|
||||
)
|
||||
suspend inline fun <T, R> R.safely(
|
||||
block: suspend R.() -> T
|
||||
): T = safely<T> { block() }
|
||||
@@ -137,11 +168,19 @@ val defaultSafelyWithoutExceptionHandlerWithNull: ExceptionHandler<Nothing?> = {
|
||||
* Shortcut for [safely] with exception handler, that as expected must return null in case of impossible creating of
|
||||
* result from exception (instead of throwing it, by default always returns null)
|
||||
*/
|
||||
@Deprecated(
|
||||
"This function become redundant since coroutines correctly handling throwing exceptions",
|
||||
replaceWith = ReplaceWith("runCatching(block).replaceIfFailure { onException(it) }.getOrNull()")
|
||||
)
|
||||
suspend fun <T> safelyWithoutExceptions(
|
||||
onException: ExceptionHandler<T> = defaultSafelyExceptionHandler,
|
||||
block: suspend () -> T
|
||||
): T? = runCatchingSafely(onException, block).getOrNull()
|
||||
|
||||
@Deprecated(
|
||||
"This function become redundant since coroutines correctly handling throwing exceptions",
|
||||
replaceWith = ReplaceWith("runCatching(block).replaceIfFailure { onException(it) }.getOrNull()")
|
||||
)
|
||||
suspend fun <T> runCatchingSafelyWithoutExceptions(
|
||||
onException: ExceptionHandler<T?> = defaultSafelyExceptionHandler,
|
||||
block: suspend () -> T
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import dev.inmo.kslog.common.KSLog
|
||||
import dev.inmo.kslog.common.e
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
fun CoroutineScope.launchLogging(
|
||||
errorMessageBuilder: CoroutineScope.(Throwable) -> Any = { "Something web wrong" },
|
||||
logger: KSLog = KSLog,
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
block: suspend CoroutineScope.() -> Unit
|
||||
) = launch(context, start) {
|
||||
runCatching { block() }.onFailure {
|
||||
logger.e(it) { errorMessageBuilder(it) }
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
fun CoroutineScope.launchLoggingDropExceptions(
|
||||
errorMessageBuilder: CoroutineScope.(Throwable) -> Any = { "Something web wrong" },
|
||||
logger: KSLog = KSLog,
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
block: suspend CoroutineScope.() -> Unit
|
||||
) = launch(context, start) {
|
||||
runCatching { block() }.onFailure {
|
||||
logger.e(it) { errorMessageBuilder(it) }
|
||||
} // just dropping exception
|
||||
}
|
||||
|
||||
fun <T> CoroutineScope.asyncLogging(
|
||||
errorMessageBuilder: CoroutineScope.(Throwable) -> Any = { "Something web wrong" },
|
||||
logger: KSLog = KSLog,
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
block: suspend CoroutineScope.() -> T
|
||||
) = async(context, start) {
|
||||
runCatching { block() }.onFailure {
|
||||
logger.e(it) { errorMessageBuilder(it) }
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
fun <T> CoroutineScope.asyncLoggingDropExceptions(
|
||||
errorMessageBuilder: CoroutineScope.(Throwable) -> Any = { "Something web wrong" },
|
||||
logger: KSLog = KSLog,
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
block: suspend CoroutineScope.() -> T
|
||||
) = async(context, start) {
|
||||
runCatching { block() }.onFailure {
|
||||
logger.e(it) { errorMessageBuilder(it) }
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,10 @@ import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
@Deprecated(
|
||||
"This method will be removed soon. Use launchLogging instead",
|
||||
ReplaceWith("this.launchLogging(context = context, start = start, block = block)")
|
||||
)
|
||||
fun CoroutineScope.launchSafely(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
@@ -15,6 +19,10 @@ fun CoroutineScope.launchSafely(
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"This method will be removed soon. Use launchLoggingDropExceptions instead",
|
||||
ReplaceWith("this.launchLoggingDropExceptions(context = context, start = start, block = block)")
|
||||
)
|
||||
fun CoroutineScope.launchSafelyWithoutExceptions(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
@@ -26,6 +34,10 @@ fun CoroutineScope.launchSafelyWithoutExceptions(
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"This method will be removed soon. Use asyncLogging instead",
|
||||
ReplaceWith("this.asyncLogging(context = context, start = start, block = block)")
|
||||
)
|
||||
fun <T> CoroutineScope.asyncSafely(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
@@ -37,6 +49,10 @@ fun <T> CoroutineScope.asyncSafely(
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"This method will be removed soon. Use asyncLoggingDropExceptions instead",
|
||||
ReplaceWith("this.asyncLoggingDropExceptions(context = context, start = start, block = block)")
|
||||
)
|
||||
fun <T> CoroutineScope.asyncSafelyWithoutExceptions(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
inline fun <T> Result<T>.replaceIfFailure(onException: (Throwable) -> T) = if (isSuccess) { this } else { runCatching { onException(exceptionOrNull()!!) } }
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import dev.inmo.kslog.common.KSLog
|
||||
import dev.inmo.kslog.common.e
|
||||
|
||||
inline fun <T, R> R.runCatchingLogging(
|
||||
noinline errorMessageBuilder: R.(Throwable) -> Any = { "Something web wrong" },
|
||||
logger: KSLog = KSLog,
|
||||
block: R.() -> T
|
||||
) = runCatching(block).onFailure {
|
||||
logger.e(it) { errorMessageBuilder(it) }
|
||||
}
|
||||
@@ -128,8 +128,10 @@ open class DefaultStatesMachine <T: State>(
|
||||
*/
|
||||
override fun start(scope: CoroutineScope): Job {
|
||||
val supervisorScope = scope.LinkedSupervisorScope()
|
||||
supervisorScope.launchSafelyWithoutExceptions {
|
||||
(statesManager.getActiveStates().asFlow() + statesManager.onStartChain).subscribeSafelyWithoutExceptions(supervisorScope) {
|
||||
supervisorScope.launchLoggingDropExceptions {
|
||||
(statesManager.getActiveStates().asFlow() + statesManager.onStartChain).subscribeSafelyWithoutExceptions(
|
||||
supervisorScope
|
||||
) {
|
||||
supervisorScope.launch { performStateUpdate(Optional.absent(), it, supervisorScope) }
|
||||
}
|
||||
statesManager.onChainStateUpdated.subscribeSafelyWithoutExceptions(supervisorScope) {
|
||||
@@ -140,7 +142,7 @@ open class DefaultStatesMachine <T: State>(
|
||||
statesJobsMutex.withLock {
|
||||
val stateInMap = statesJobs.keys.firstOrNull { stateInMap -> stateInMap == removedState }
|
||||
if (stateInMap === removedState) {
|
||||
statesJobs[stateInMap] ?.cancel()
|
||||
statesJobs[stateInMap]?.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,5 +15,5 @@ crypto_js_version=4.1.1
|
||||
# Project data
|
||||
|
||||
group=dev.inmo
|
||||
version=0.24.6
|
||||
android_code_version=286
|
||||
version=0.24.7
|
||||
android_code_version=287
|
||||
|
||||
@@ -4,18 +4,18 @@ kt = "2.1.10"
|
||||
kt-serialization = "1.8.0"
|
||||
kt-coroutines = "1.10.1"
|
||||
|
||||
kslog = "1.4.0"
|
||||
kslog = "1.4.1"
|
||||
|
||||
jb-compose = "1.7.3"
|
||||
jb-exposed = "0.58.0"
|
||||
jb-exposed = "0.59.0"
|
||||
jb-dokka = "2.0.0"
|
||||
|
||||
sqlite = "3.48.0.0"
|
||||
sqlite = "3.49.1.0"
|
||||
|
||||
korlibs = "5.4.0"
|
||||
uuid = "0.8.4"
|
||||
|
||||
ktor = "3.0.3"
|
||||
ktor = "3.1.0"
|
||||
|
||||
gh-release = "2.5.2"
|
||||
|
||||
@@ -23,21 +23,20 @@ koin = "4.0.2"
|
||||
|
||||
okio = "3.10.2"
|
||||
|
||||
ksp = "2.1.10-1.0.29"
|
||||
ksp = "2.1.10-1.0.30"
|
||||
kotlin-poet = "1.18.1"
|
||||
|
||||
versions = "0.51.0"
|
||||
|
||||
android-gradle = "8.2.2"
|
||||
android-gradle = "8.7.+"
|
||||
dexcount = "4.0.0"
|
||||
|
||||
android-coreKtx = "1.15.0"
|
||||
android-recyclerView = "1.4.0"
|
||||
android-appCompat = "1.7.0"
|
||||
android-fragment = "1.8.5"
|
||||
android-fragment = "1.8.6"
|
||||
android-espresso = "3.6.1"
|
||||
android-test = "1.2.1"
|
||||
android-compose-material3 = "1.3.0"
|
||||
|
||||
android-props-minSdk = "21"
|
||||
android-props-compileSdk = "35"
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
if (ext.getProperties()["do_publish"] == false) {
|
||||
return
|
||||
}
|
||||
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
task javadocsJar(type: Jar) {
|
||||
@@ -19,29 +23,29 @@ publishing {
|
||||
}
|
||||
|
||||
developers {
|
||||
|
||||
|
||||
developer {
|
||||
id = "InsanusMokrassar"
|
||||
name = "Aleksei Ovsiannikov"
|
||||
email = "ovsyannikov.alexey95@gmail.com"
|
||||
}
|
||||
|
||||
|
||||
|
||||
developer {
|
||||
id = "000Sanya"
|
||||
name = "Syrov Aleksandr"
|
||||
email = "000sanya.000sanya@gmail.com"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
licenses {
|
||||
|
||||
|
||||
license {
|
||||
name = "Apache Software License 2.0"
|
||||
url = "https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
@@ -49,51 +53,51 @@ publishing {
|
||||
maven {
|
||||
name = "GithubPackages"
|
||||
url = uri("https://maven.pkg.github.com/InsanusMokrassar/MicroUtils")
|
||||
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
|
||||
password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
if ((project.hasProperty('INMONEXUS_USER') || System.getenv('INMONEXUS_USER') != null) && (project.hasProperty('INMONEXUS_PASSWORD') || System.getenv('INMONEXUS_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "InmoNexus"
|
||||
url = uri("https://nexus.inmo.dev/repository/maven-releases/")
|
||||
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('INMONEXUS_USER') ? project.property('INMONEXUS_USER') : System.getenv('INMONEXUS_USER')
|
||||
password = project.hasProperty('INMONEXUS_PASSWORD') ? project.property('INMONEXUS_PASSWORD') : System.getenv('INMONEXUS_PASSWORD')
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "sonatype"
|
||||
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
|
||||
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
|
||||
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (project.hasProperty("signing.gnupg.keyName")) {
|
||||
apply plugin: 'signing'
|
||||
|
||||
|
||||
signing {
|
||||
useGpgCmd()
|
||||
|
||||
|
||||
sign publishing.publications
|
||||
}
|
||||
|
||||
|
||||
task signAll {
|
||||
tasks.withType(Sign).forEach {
|
||||
dependsOn(it)
|
||||
|
||||
@@ -5,6 +5,8 @@ plugins {
|
||||
id "com.google.devtools.ksp"
|
||||
}
|
||||
|
||||
ext.do_publish = false
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
|
||||
|
||||
@@ -12,15 +12,22 @@ fun KSDeclaration.writeFile(
|
||||
suffix: String = "",
|
||||
relatedPath: String = "",
|
||||
force: Boolean = false,
|
||||
forceUppercase: Boolean = true,
|
||||
fileSpecBuilder: () -> FileSpec
|
||||
) {
|
||||
val containingFile = containingFile!!
|
||||
val simpleName = if (forceUppercase) {
|
||||
val rawSimpleName = simpleName.asString()
|
||||
rawSimpleName.replaceFirst(rawSimpleName.first().toString(), rawSimpleName.first().uppercase())
|
||||
} else {
|
||||
simpleName.asString()
|
||||
}
|
||||
File(
|
||||
File(
|
||||
File(containingFile.filePath).parent,
|
||||
relatedPath
|
||||
),
|
||||
"$prefix${simpleName.asString()}$suffix.kt"
|
||||
"$prefix${simpleName}$suffix.kt"
|
||||
).takeIf { force || !it.exists() } ?.apply {
|
||||
parentFile.mkdirs()
|
||||
val fileSpec = fileSpecBuilder()
|
||||
|
||||
@@ -5,6 +5,8 @@ plugins {
|
||||
id "com.google.devtools.ksp"
|
||||
}
|
||||
|
||||
ext.do_publish = false
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
|
||||
|
||||
@@ -77,6 +77,11 @@ class Processor(
|
||||
if (it.isVararg) {
|
||||
addModifiers(KModifier.VARARG)
|
||||
}
|
||||
it.annotations.forEach {
|
||||
if (it.shortName.asString() == GenerationVariant::class.simpleName) return@forEach
|
||||
|
||||
addAnnotation(it.toAnnotationSpec(omitDefaultValues = false))
|
||||
}
|
||||
}
|
||||
.build() to it.hasDefault
|
||||
}
|
||||
@@ -92,11 +97,16 @@ class Processor(
|
||||
val funSpec = FunSpec.builder(ksFunctionDeclaration.simpleName.asString()).apply {
|
||||
modifiers.addAll(ksFunctionDeclaration.modifiers.mapNotNull { it.toKModifier() })
|
||||
ksFunctionDeclaration.annotations.forEach {
|
||||
if (it.shortName.asString() == GenerateVariations::class.simpleName) return@forEach
|
||||
|
||||
addAnnotation(it.toAnnotationSpec(omitDefaultValues = false))
|
||||
}
|
||||
ksFunctionDeclaration.extensionReceiver ?.let {
|
||||
receiver(it.toTypeName())
|
||||
}
|
||||
ksFunctionDeclaration.returnType ?.let {
|
||||
returns(it.toTypeName())
|
||||
}
|
||||
}
|
||||
baseFunctionParameters.forEach { (parameter, hasDefault) ->
|
||||
if (hasDefault) {
|
||||
@@ -138,6 +148,7 @@ class Processor(
|
||||
accumulatedGeneration.receiverType ?.let {
|
||||
receiver(it)
|
||||
}
|
||||
returns(accumulatedGeneration.returnType)
|
||||
accumulatedGeneration.parameters.forEach {
|
||||
val actualName = if (variation.argName.isEmpty()) it.name else variation.argName
|
||||
parameters.add(
|
||||
@@ -169,8 +180,15 @@ class Processor(
|
||||
defaults[it.name] = defaultValueString
|
||||
}
|
||||
} else {
|
||||
it.toBuilder()
|
||||
it.toBuilder().apply {
|
||||
defaults[it.name] = it.name
|
||||
}
|
||||
})
|
||||
.apply {
|
||||
it.annotations.forEach {
|
||||
addAnnotation(it)
|
||||
}
|
||||
}
|
||||
.build()
|
||||
)
|
||||
}
|
||||
@@ -206,7 +224,7 @@ class Processor(
|
||||
it.writeFile(prefix = prefix, suffix = "GeneratedVariation") {
|
||||
FileSpec.builder(
|
||||
it.packageName.asString(),
|
||||
"${it.simpleName.getShortName()}GeneratedVariation"
|
||||
"${it.simpleName.getShortName().let { it.replaceFirst(it.first().toString(), it.first().uppercase()) }}GeneratedVariation"
|
||||
).apply {
|
||||
addFileComment(
|
||||
"""
|
||||
|
||||
@@ -5,6 +5,8 @@ plugins {
|
||||
id "com.google.devtools.ksp"
|
||||
}
|
||||
|
||||
ext.do_publish = false
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
|
||||
|
||||
@@ -47,3 +47,15 @@ public suspend fun SimpleType.sample2(
|
||||
): Unit = sample2(
|
||||
arg1 = arg1, arg2 = with(arg22) {toInt()}, arg3 = arg3
|
||||
)
|
||||
|
||||
public suspend fun SimpleType.sample2(arg12: Int, arg22: String): Unit = sample2(
|
||||
arg12 = arg12, arg2 = with(arg22) {toInt()}
|
||||
)
|
||||
|
||||
public suspend fun SimpleType.sample2(
|
||||
arg12: Int,
|
||||
arg22: String,
|
||||
arg3: Boolean,
|
||||
): Unit = sample2(
|
||||
arg12 = arg12, arg2 = with(arg22) {toInt()}, arg3 = arg3
|
||||
)
|
||||
@@ -2,7 +2,7 @@ package dev.inmo.micro_utils.ktor.client
|
||||
|
||||
import dev.inmo.micro_utils.common.MPPFile
|
||||
import dev.inmo.micro_utils.coroutines.LinkedSupervisorJob
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import dev.inmo.micro_utils.ktor.common.TemporalFileId
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.content.*
|
||||
@@ -27,7 +27,7 @@ suspend fun tempUpload(
|
||||
val request = XMLHttpRequest()
|
||||
request.responseType = XMLHttpRequestResponseType.TEXT
|
||||
request.upload.onprogress = {
|
||||
subscope.launchSafelyWithoutExceptions { onUpload.onProgress(it.loaded.toLong(), it.total.toLong()) }
|
||||
subscope.launchLoggingDropExceptions { onUpload.onProgress(it.loaded.toLong(), it.total.toLong()) }
|
||||
}
|
||||
request.onload = {
|
||||
if (request.status == 200.toShort()) {
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.inmo.micro_utils.ktor.client
|
||||
|
||||
import dev.inmo.micro_utils.common.MPPFile
|
||||
import dev.inmo.micro_utils.coroutines.LinkedSupervisorJob
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.content.*
|
||||
import io.ktor.http.Headers
|
||||
@@ -66,7 +66,7 @@ actual suspend fun <T> HttpClient.uniUpload(
|
||||
}
|
||||
request.responseType = XMLHttpRequestResponseType.TEXT
|
||||
request.upload.onprogress = {
|
||||
subscope.launchSafelyWithoutExceptions { onUpload.onProgress(it.loaded.toLong(), it.total.toLong()) }
|
||||
subscope.launchLoggingDropExceptions { onUpload.onProgress(it.loaded.toLong(), it.total.toLong()) }
|
||||
}
|
||||
request.onload = {
|
||||
if (request.status == 200.toShort()) {
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.inmo.micro_utils.ktor.server
|
||||
import com.benasher44.uuid.uuid4
|
||||
import dev.inmo.micro_utils.common.FileName
|
||||
import dev.inmo.micro_utils.common.MPPFile
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import dev.inmo.micro_utils.ktor.common.DefaultTemporalFilesSubPath
|
||||
import dev.inmo.micro_utils.ktor.common.TemporalFileId
|
||||
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
|
||||
@@ -44,7 +44,7 @@ class TemporalFilesRoutingConfigurator(
|
||||
filesMap: MutableMap<TemporalFileId, MPPFile>,
|
||||
filesMutex: Mutex,
|
||||
onNewFileFlow: Flow<TemporalFileId>
|
||||
): Job = scope.launchSafelyWithoutExceptions {
|
||||
): Job = scope.launchLoggingDropExceptions {
|
||||
while (currentCoroutineContext().isActive) {
|
||||
val filesWithCreationInfo = filesMap.mapNotNull { (fileId, file) ->
|
||||
fileId to ((Files.getAttribute(file.toPath(), "creationTime") as? FileTime) ?.toMillis() ?: return@mapNotNull null)
|
||||
|
||||
@@ -2,19 +2,19 @@ package dev.inmo.micro_utils.pagination
|
||||
|
||||
import org.jetbrains.exposed.sql.*
|
||||
|
||||
fun Query.paginate(with: Pagination, orderBy: Pair<Expression<*>, SortOrder>? = null) = limit(
|
||||
with.size,
|
||||
with.firstIndex.toLong()
|
||||
).let {
|
||||
if (orderBy != null) {
|
||||
it.orderBy(
|
||||
orderBy.first,
|
||||
orderBy.second
|
||||
)
|
||||
} else {
|
||||
it
|
||||
fun Query.paginate(with: Pagination, orderBy: Pair<Expression<*>, SortOrder>? = null) =
|
||||
limit(with.size)
|
||||
.offset(with.firstIndex.toLong())
|
||||
.let {
|
||||
if (orderBy != null) {
|
||||
it.orderBy(
|
||||
orderBy.first,
|
||||
orderBy.second
|
||||
)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Query.paginate(with: Pagination, orderBy: Expression<*>?, reversed: Boolean = false) = paginate(
|
||||
with,
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.inmo.micro_utils.repos.cache.full
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
@@ -17,7 +17,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
open class FullReadCRUDCacheRepo<ObjectType, IdType>(
|
||||
protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
|
||||
protected open val kvCache: KeyValueRepo<IdType, ObjectType>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker(),
|
||||
protected open val locker: SmartRWLocker = SmartRWLocker(),
|
||||
protected open val idGetter: (ObjectType) -> IdType
|
||||
) : ReadCRUDRepo<ObjectType, IdType>, FullCacheRepo {
|
||||
protected suspend inline fun <T> doOrTakeAndActualize(
|
||||
@@ -95,11 +95,11 @@ fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
|
||||
|
||||
open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
|
||||
kvCache: KeyValueRepo<IdType, ObjectType>,
|
||||
override val kvCache: KeyValueRepo<IdType, ObjectType>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
idGetter: (ObjectType) -> IdType
|
||||
override val locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
override val idGetter: (ObjectType) -> IdType
|
||||
) : FullReadCRUDCacheRepo<ObjectType, IdType>(
|
||||
parentRepo,
|
||||
kvCache,
|
||||
@@ -116,7 +116,7 @@ open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
CRUDRepo<ObjectType, IdType, InputValueType> {
|
||||
init {
|
||||
if (!skipStartInvalidate) {
|
||||
scope.launchSafelyWithoutExceptions {
|
||||
scope.launchLoggingDropExceptions {
|
||||
if (locker.writeMutex.isLocked) {
|
||||
initialInvalidate()
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.inmo.micro_utils.repos.cache.full
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
@@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.*
|
||||
open class FullReadKeyValueCacheRepo<Key,Value>(
|
||||
protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
|
||||
protected open val kvCache: KeyValueRepo<Key, Value>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker()
|
||||
protected open val locker: SmartRWLocker = SmartRWLocker()
|
||||
) : ReadKeyValueRepo<Key, Value>, FullCacheRepo {
|
||||
protected suspend inline fun <T> doOrTakeAndActualize(
|
||||
action: KeyValueRepo<Key, Value>.() -> Optional<T>,
|
||||
@@ -127,10 +127,10 @@ fun <Key, Value> WriteKeyValueRepo<Key, Value>.caching(
|
||||
|
||||
open class FullKeyValueCacheRepo<Key,Value>(
|
||||
override val parentRepo: KeyValueRepo<Key, Value>,
|
||||
kvCache: KeyValueRepo<Key, Value>,
|
||||
override val kvCache: KeyValueRepo<Key, Value>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
override val locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
) : //FullWriteKeyValueCacheRepo<Key,Value>(parentRepo, kvCache, scope),
|
||||
KeyValueRepo<Key,Value>,
|
||||
WriteKeyValueRepo<Key,Value> by parentRepo,
|
||||
@@ -141,7 +141,7 @@ open class FullKeyValueCacheRepo<Key,Value>(
|
||||
) {
|
||||
init {
|
||||
if (!skipStartInvalidate) {
|
||||
scope.launchSafelyWithoutExceptions {
|
||||
scope.launchLoggingDropExceptions {
|
||||
if (locker.writeMutex.isLocked) {
|
||||
initialInvalidate()
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.inmo.micro_utils.repos.cache.full
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
@@ -18,7 +18,7 @@ import kotlinx.coroutines.flow.*
|
||||
open class FullReadKeyValuesCacheRepo<Key,Value>(
|
||||
protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
|
||||
protected open val kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker(),
|
||||
protected open val locker: SmartRWLocker = SmartRWLocker(),
|
||||
) : ReadKeyValuesRepo<Key, Value>, FullCacheRepo {
|
||||
protected suspend inline fun <T> doOrTakeAndActualize(
|
||||
action: KeyValueRepo<Key, List<Value>>.() -> Optional<T>,
|
||||
@@ -201,16 +201,16 @@ fun <Key, Value> WriteKeyValuesRepo<Key, Value>.caching(
|
||||
|
||||
open class FullKeyValuesCacheRepo<Key,Value>(
|
||||
override val parentRepo: KeyValuesRepo<Key, Value>,
|
||||
kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
override val kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
override val locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
) : KeyValuesRepo<Key, Value>,
|
||||
FullReadKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, locker),
|
||||
WriteKeyValuesRepo<Key, Value> by parentRepo {
|
||||
init {
|
||||
if (!skipStartInvalidate) {
|
||||
scope.launchSafelyWithoutExceptions {
|
||||
scope.launchLoggingDropExceptions {
|
||||
if (locker.writeMutex.isLocked) {
|
||||
initialInvalidate()
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.inmo.micro_utils.repos.cache.full.direct
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
@@ -17,7 +17,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
open class DirectFullReadCRUDCacheRepo<ObjectType, IdType>(
|
||||
protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
|
||||
protected open val kvCache: KeyValueRepo<IdType, ObjectType>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker(),
|
||||
protected open val locker: SmartRWLocker = SmartRWLocker(),
|
||||
protected open val idGetter: (ObjectType) -> IdType
|
||||
) : ReadCRUDRepo<ObjectType, IdType>, DirectFullCacheRepo {
|
||||
protected open suspend fun actualizeAll() {
|
||||
@@ -61,10 +61,10 @@ fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.directlyCached(
|
||||
|
||||
open class DirectFullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
|
||||
kvCache: KeyValueRepo<IdType, ObjectType>,
|
||||
override val kvCache: KeyValueRepo<IdType, ObjectType>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
override val locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
idGetter: (ObjectType) -> IdType
|
||||
) : DirectFullReadCRUDCacheRepo<ObjectType, IdType>(
|
||||
parentRepo,
|
||||
@@ -82,7 +82,7 @@ open class DirectFullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
CRUDRepo<ObjectType, IdType, InputValueType> {
|
||||
init {
|
||||
if (!skipStartInvalidate) {
|
||||
scope.launchSafelyWithoutExceptions {
|
||||
scope.launchLoggingDropExceptions {
|
||||
if (locker.writeMutex.isLocked) {
|
||||
initialInvalidate()
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package dev.inmo.micro_utils.repos.cache.full.direct
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
@@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.onEach
|
||||
open class DirectFullReadKeyValueCacheRepo<Key, Value>(
|
||||
protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
|
||||
protected open val kvCache: KeyValueRepo<Key, Value>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker()
|
||||
protected open val locker: SmartRWLocker = SmartRWLocker()
|
||||
) : DirectFullCacheRepo, ReadKeyValueRepo<Key, Value> {
|
||||
protected open suspend fun actualizeAll() {
|
||||
kvCache.actualizeAll(parentRepo, locker)
|
||||
@@ -102,10 +102,10 @@ fun <Key, Value> WriteKeyValueRepo<Key, Value>.directlyCached(
|
||||
|
||||
open class DirectFullKeyValueCacheRepo<Key, Value>(
|
||||
override val parentRepo: KeyValueRepo<Key, Value>,
|
||||
kvCache: KeyValueRepo<Key, Value>,
|
||||
override val kvCache: KeyValueRepo<Key, Value>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
override val locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
) : DirectFullCacheRepo,
|
||||
KeyValueRepo<Key, Value> ,
|
||||
WriteKeyValueRepo<Key, Value> by DirectFullWriteKeyValueCacheRepo(
|
||||
@@ -117,7 +117,7 @@ open class DirectFullKeyValueCacheRepo<Key, Value>(
|
||||
DirectFullReadKeyValueCacheRepo<Key, Value>(parentRepo, kvCache, locker) {
|
||||
init {
|
||||
if (!skipStartInvalidate) {
|
||||
scope.launchSafelyWithoutExceptions {
|
||||
scope.launchLoggingDropExceptions {
|
||||
if (locker.writeMutex.isLocked) {
|
||||
initialInvalidate()
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.inmo.micro_utils.repos.cache.full.direct
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
@@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.*
|
||||
open class DirectFullReadKeyValuesCacheRepo<Key,Value>(
|
||||
protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
|
||||
protected open val kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker(),
|
||||
protected open val locker: SmartRWLocker = SmartRWLocker(),
|
||||
) : ReadKeyValuesRepo<Key, Value>, DirectFullCacheRepo {
|
||||
protected open suspend fun actualizeKey(k: Key) {
|
||||
kvCache.actualizeAll(locker = locker, clearMode = ActualizeAllClearMode.Never) {
|
||||
@@ -136,16 +136,16 @@ fun <Key, Value> WriteKeyValuesRepo<Key, Value>.directlyCached(
|
||||
|
||||
open class DirectFullKeyValuesCacheRepo<Key,Value>(
|
||||
override val parentRepo: KeyValuesRepo<Key, Value>,
|
||||
kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
override val kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
override val locker: SmartRWLocker = SmartRWLocker(writeIsLocked = !skipStartInvalidate),
|
||||
) : KeyValuesRepo<Key, Value>,
|
||||
DirectFullReadKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, locker),
|
||||
WriteKeyValuesRepo<Key, Value> by parentRepo {
|
||||
init {
|
||||
if (!skipStartInvalidate) {
|
||||
scope.launchSafelyWithoutExceptions {
|
||||
scope.launchLoggingDropExceptions {
|
||||
if (locker.writeMutex.isLocked) {
|
||||
initialInvalidate()
|
||||
} else {
|
||||
|
||||
@@ -137,7 +137,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||
override suspend fun deleteById(ids: List<IdType>) {
|
||||
onBeforeDelete(ids)
|
||||
transaction(db = database) {
|
||||
val deleted = deleteWhere(null, null) { selectByIds(it, ids) }
|
||||
val deleted = deleteWhere { selectByIds(it, ids) }
|
||||
if (deleted == ids.size) {
|
||||
ids
|
||||
} else {
|
||||
|
||||
@@ -4,7 +4,6 @@ import dev.inmo.micro_utils.repos.KeyValuesRepo
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.*
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.statements.InsertStatement
|
||||
import org.jetbrains.exposed.sql.statements.UpdateBuilder
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
@@ -57,18 +56,48 @@ abstract class AbstractExposedKeyValuesRepo<Key, Value>(
|
||||
}
|
||||
}
|
||||
|
||||
transaction(database) {
|
||||
val (oldObjects, insertedResults) = transaction(database) {
|
||||
val oldObjects = selectAll().where { selectByIds(toSet.keys.toList()) }.map { it.asKey to it.asObject }
|
||||
|
||||
deleteWhere {
|
||||
selectByIds(it, toSet.keys.toList())
|
||||
}
|
||||
batchInsert(
|
||||
val inserted = batchInsert(
|
||||
prepreparedData,
|
||||
) { (k, v) ->
|
||||
insert(k, v, this)
|
||||
}.map {
|
||||
it.asKey to it.asObject
|
||||
}
|
||||
}.forEach { _onNewValue.emit(it) }
|
||||
oldObjects to inserted
|
||||
}.let {
|
||||
val mappedFirst = it
|
||||
.first
|
||||
.asSequence()
|
||||
.groupBy { it.first }
|
||||
.mapValues { it.value.map { it.second }.toSet() }
|
||||
val mappedSecond = it
|
||||
.second
|
||||
.asSequence()
|
||||
.groupBy { it.first }
|
||||
.mapValues { it.value.map { it.second }.toSet() }
|
||||
mappedFirst to mappedSecond
|
||||
}
|
||||
val deletedResults = oldObjects.mapNotNull { (k, vs) ->
|
||||
k to vs.filter { v ->
|
||||
insertedResults[k] ?.contains(v) != true
|
||||
}.ifEmpty { return@mapNotNull null }
|
||||
}
|
||||
deletedResults.forEach { (k, vs) ->
|
||||
vs.forEach { v ->
|
||||
_onValueRemoved.emit(k to v)
|
||||
}
|
||||
}
|
||||
insertedResults.forEach { (k, vs) ->
|
||||
vs.forEach { v ->
|
||||
_onNewValue.emit(k to v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun remove(toRemove: Map<Key, List<Value>>) {
|
||||
|
||||
Reference in New Issue
Block a user