mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-04 06:00:22 +00:00 
			
		
		
		
	Compare commits
	
		
			39 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ce15ff4e0a | |||
| 382b956beb | |||
| 36deab4909 | |||
| 550fc59d9d | |||
| 9100a57458 | |||
| 74d9bbccd9 | |||
| 75e602a349 | |||
| e73644db10 | |||
| 148e6bdae7 | |||
| 1b540199f0 | |||
| 30b70e9984 | |||
| c1557cff27 | |||
| 2d662f91b3 | |||
| c4a08e52e5 | |||
| 08c371c142 | |||
| 8e62dd460c | |||
| 1f9302dc94 | |||
| 16f445f699 | |||
| b4abd564ec | |||
| 14ffafb0a7 | |||
| e0cc780887 | |||
| ab7d277167 | |||
| 8308c1df4d | |||
| 12c29f5180 | |||
| 2963098870 | |||
| 9f56b0a26d | |||
| 75851312fd | |||
| 3a3be138a5 | |||
| fb7d1f18b0 | |||
| d1c6c7696a | |||
| 5f38d9635d | |||
| 8185ea87b1 | |||
| 98bd07d025 | |||
| c502c70a21 | |||
| d933dc532b | |||
| 42594f0656 | |||
| 4b83ca19c3 | |||
| bab13f5e83 | |||
| 14c5f5a26c | 
							
								
								
									
										21
									
								
								.github/workflows/dokka_push.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								.github/workflows/dokka_push.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					name: Publish KDocs
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    branches:
 | 
				
			||||||
 | 
					      - master
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  publishing:
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
 | 
					      - uses: actions/setup-java@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          java-version: 1.8
 | 
				
			||||||
 | 
					      - name: Build
 | 
				
			||||||
 | 
					        run: ./gradlew dokkaHtml
 | 
				
			||||||
 | 
					      - name: Publish KDocs
 | 
				
			||||||
 | 
					        uses: peaceiris/actions-gh-pages@v3
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          github_token: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
 | 
					          publish_dir: ./dokka/build/dokka/html
 | 
				
			||||||
 | 
					          publish_branch: kdocs
 | 
				
			||||||
							
								
								
									
										16
									
								
								.github/workflows/gradle_build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								.github/workflows/gradle_build.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,16 +0,0 @@
 | 
				
			|||||||
name: Build
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
on: [push]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
jobs:
 | 
					 | 
				
			||||||
  build:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      - name: Set up JDK 1.8
 | 
					 | 
				
			||||||
        uses: actions/setup-java@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          java-version: 1.8
 | 
					 | 
				
			||||||
      - name: Build with Gradle
 | 
					 | 
				
			||||||
        run: ./gradlew build
 | 
					 | 
				
			||||||
							
								
								
									
										24
									
								
								.github/workflows/packages_push.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.github/workflows/packages_push.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					name: Publish package to GitHub Packages
 | 
				
			||||||
 | 
					on: [push]
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  publishing:
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
 | 
					      - uses: actions/setup-java@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          java-version: 1.8
 | 
				
			||||||
 | 
					      - name: Rewrite version
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
 | 
				
			||||||
 | 
					          cat gradle.properties | sed -e "s/^version=\([0-9\.]*\)/version=\1-branch_$branch-build${{ github.run_number }}/" > gradle.properties.tmp
 | 
				
			||||||
 | 
					          rm gradle.properties
 | 
				
			||||||
 | 
					          mv gradle.properties.tmp gradle.properties
 | 
				
			||||||
 | 
					      - name: Build
 | 
				
			||||||
 | 
					        run: ./gradlew build
 | 
				
			||||||
 | 
					      - name: Publish
 | 
				
			||||||
 | 
					        run: ./gradlew --no-parallel publishAllPublicationsToGithubPackagesRepository -x signJsPublication -x signJvmPublication -x signKotlinMultiplatformPublication -x signMetadataPublication -x signAndroidDebugPublication -x signAndroidReleasePublication -x signKotlinMultiplatformPublication
 | 
				
			||||||
 | 
					        env:
 | 
				
			||||||
 | 
					          GITHUBPACKAGES_USER: ${{ github.actor }}
 | 
				
			||||||
 | 
					          GITHUBPACKAGES_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
							
								
								
									
										71
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,7 +1,78 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.4.33
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Ktor`: `1.5.2` -> `1.5.3`
 | 
				
			||||||
 | 
					* `Coroutines`
 | 
				
			||||||
 | 
					    * Add `WeakJob` workaround:
 | 
				
			||||||
 | 
					        * `CoroutineScope#weakLaunch`
 | 
				
			||||||
 | 
					        * `CoroutineScope#weakAsync`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.4.32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Kotlin Exposed`: `0.29.1` -> `0.30.1`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.4.31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Kotlin`: `1.4.31` -> `1.4.32`
 | 
				
			||||||
 | 
					* `Pagination`:
 | 
				
			||||||
 | 
					    * New extensions `PaginationResult.changeResultsUnchecked` and `PaginationResult.changeResults` for mapping results
 | 
				
			||||||
 | 
					    with the same parameters, but different data
 | 
				
			||||||
 | 
					    * Extension `PaginationResult.thisPageIfNotEmpty` now is typed and will return `PaginationResult?` with the same
 | 
				
			||||||
 | 
					    generic type as income `PaginationResult`
 | 
				
			||||||
 | 
					    * New extension `PaginationResult.currentPageIfNotEmpty` - shortcut for `PaginationResult.thisPageIfNotEmpty`
 | 
				
			||||||
 | 
					    * New common functions. They were created as replacements for currently available for more comfortable work
 | 
				
			||||||
 | 
					    with repos pagination:
 | 
				
			||||||
 | 
					        * `doForAll`
 | 
				
			||||||
 | 
					        * `doForAllWithNextPaging`
 | 
				
			||||||
 | 
					        * `doForAllWithCurrentPaging`
 | 
				
			||||||
 | 
					        * `getAll`
 | 
				
			||||||
 | 
					        * `getAllWithNextPaging`
 | 
				
			||||||
 | 
					        * `getAllWithCurrentPaging`
 | 
				
			||||||
 | 
					* `Coroutines`:
 | 
				
			||||||
 | 
					    * Rewrite `subscribeSafelyWithoutExceptions`
 | 
				
			||||||
 | 
					        * Now `subscribeSafelyWithoutExceptions` will use default handler instead of skipping
 | 
				
			||||||
 | 
					    * New extension `subscribeSafelySkippingExceptions`
 | 
				
			||||||
 | 
					* `Repos`
 | 
				
			||||||
 | 
					    * New subproject `repos.cache` - this subproject will contain repos with data caching mechanisms
 | 
				
			||||||
 | 
					    * Most old `doForAll` methods have been deprecated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.4.30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Klock`: `2.0.6` -> `2.0.7`
 | 
				
			||||||
 | 
					* `Pagination`:
 | 
				
			||||||
 | 
					    * New variable `defaultPaginationPageSize` has been added to be able to change default pagination size
 | 
				
			||||||
 | 
					    * Add new value `firstPageWithOneElementPagination` 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.4.29
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Coroutines`: `1.4.2` -> `1.4.3`
 | 
				
			||||||
 | 
					* `Repos`:
 | 
				
			||||||
 | 
					    * `Common`
 | 
				
			||||||
 | 
					        * `Android`:
 | 
				
			||||||
 | 
					            * New `blockingReadableTransaction`/`blockingWritableTransaction`
 | 
				
			||||||
 | 
					                * Android databases realizations now use blocking transactions where it is possible
 | 
				
			||||||
 | 
					            * Several improvements in transactions work
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.4.28
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Kotlin`: `1.4.30` -> `1.4.31`
 | 
				
			||||||
 | 
					    * `Ktor`: `1.5.1` -> `1.5.2`
 | 
				
			||||||
 | 
					* `Coroutines`
 | 
				
			||||||
 | 
					    * Add `createActionsActor`/`createSafeActionsActor` and `doWithSuspending`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.4.27
 | 
					## 0.4.27
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Repos`
 | 
				
			||||||
 | 
					    * `Exposed`
 | 
				
			||||||
 | 
					        * Fix in `AbstractExposedWriteCRUDRepo`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.4.26
 | 
					## 0.4.26
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `Versions`:
 | 
					* `Versions`:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.coroutines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
 | 
					import kotlinx.coroutines.channels.Channel
 | 
				
			||||||
 | 
					import kotlin.coroutines.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ActorAction<T> {
 | 
				
			||||||
 | 
					    suspend operator fun invoke(): T
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Planned to use with [doWithSuspending]. Will execute incoming lambdas sequentially
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see actor
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun CoroutineScope.createActionsActor() = actor<suspend () -> Unit> {
 | 
				
			||||||
 | 
					    it()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Planned to use with [doWithSuspending]. Will execute incoming lambdas sequentially
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see safeActor
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					inline fun CoroutineScope.createSafeActionsActor(
 | 
				
			||||||
 | 
					    noinline onException: ExceptionHandler<Unit> = defaultSafelyExceptionHandler
 | 
				
			||||||
 | 
					) = safeActor<suspend () -> Unit>(Channel.UNLIMITED, onException) {
 | 
				
			||||||
 | 
					    it()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Must be use with actor created by [createActionsActor] or [createSafeActionsActor]. Will send lambda which will
 | 
				
			||||||
 | 
					 * execute [action] and return result.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see suspendCoroutine
 | 
				
			||||||
 | 
					 * @see safely
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					suspend fun <T> Channel<suspend () -> Unit>.doWithSuspending(
 | 
				
			||||||
 | 
					    action: ActorAction<T>
 | 
				
			||||||
 | 
					) = suspendCoroutine<T> {
 | 
				
			||||||
 | 
					    offer {
 | 
				
			||||||
 | 
					        safely({ e -> it.resumeWithException(e) }) {
 | 
				
			||||||
 | 
					            it.resume(action())
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -25,13 +25,25 @@ inline fun <T> Flow<T>.subscribeSafely(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Use [subscribeSafelyWithoutExceptions], but all exceptions inside of [safely] will be skipped
 | 
					 * Use [subscribeSafelyWithoutExceptions], but all exceptions will be passed to [defaultSafelyExceptionHandler]
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
inline fun <T> Flow<T>.subscribeSafelyWithoutExceptions(
 | 
					inline fun <T> Flow<T>.subscribeSafelyWithoutExceptions(
 | 
				
			||||||
    scope: CoroutineScope,
 | 
					    scope: CoroutineScope,
 | 
				
			||||||
    noinline block: suspend (T) -> Unit
 | 
					    noinline block: suspend (T) -> Unit
 | 
				
			||||||
) = subscribeSafely(
 | 
					) = subscribe(scope) {
 | 
				
			||||||
    scope,
 | 
					    safelyWithoutExceptions {
 | 
				
			||||||
    {},
 | 
					        block(it)
 | 
				
			||||||
    block
 | 
					    }
 | 
				
			||||||
)
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Use [subscribeSafelyWithoutExceptions], but all exceptions inside of [safely] will be skipped
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					inline fun <T> Flow<T>.subscribeSafelySkippingExceptions(
 | 
				
			||||||
 | 
					    scope: CoroutineScope,
 | 
				
			||||||
 | 
					    noinline block: suspend (T) -> Unit
 | 
				
			||||||
 | 
					) = subscribe(scope) {
 | 
				
			||||||
 | 
					    safelyWithoutExceptions({ /* skip exceptions */ }) {
 | 
				
			||||||
 | 
					        block(it)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.coroutines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.coroutines.*
 | 
				
			||||||
 | 
					import kotlin.coroutines.CoroutineContext
 | 
				
			||||||
 | 
					import kotlin.coroutines.EmptyCoroutineContext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private fun CoroutineScope.createWeakSubScope() = CoroutineScope(coroutineContext.minusKey(Job)).also { newScope ->
 | 
				
			||||||
 | 
					    coroutineContext.job.invokeOnCompletion { newScope.cancel() }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun CoroutineScope.weakLaunch(
 | 
				
			||||||
 | 
					    context: CoroutineContext = EmptyCoroutineContext,
 | 
				
			||||||
 | 
					    start: CoroutineStart = CoroutineStart.DEFAULT,
 | 
				
			||||||
 | 
					    block: suspend CoroutineScope.() -> Unit
 | 
				
			||||||
 | 
					): Job {
 | 
				
			||||||
 | 
					    val scope = createWeakSubScope()
 | 
				
			||||||
 | 
					    val job = scope.launch(context, start, block)
 | 
				
			||||||
 | 
					    job.invokeOnCompletion { scope.cancel() }
 | 
				
			||||||
 | 
					    return job
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun <T> CoroutineScope.weakAsync(
 | 
				
			||||||
 | 
					    context: CoroutineContext = EmptyCoroutineContext,
 | 
				
			||||||
 | 
					    start: CoroutineStart = CoroutineStart.DEFAULT,
 | 
				
			||||||
 | 
					    block: suspend CoroutineScope.() -> T
 | 
				
			||||||
 | 
					): Deferred<T> {
 | 
				
			||||||
 | 
					    val scope = createWeakSubScope()
 | 
				
			||||||
 | 
					    val deferred = scope.async(context, start, block)
 | 
				
			||||||
 | 
					    deferred.invokeOnCompletion { scope.cancel() }
 | 
				
			||||||
 | 
					    return deferred
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.coroutines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.coroutines.*
 | 
				
			||||||
 | 
					import org.junit.Test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class WeakJob {
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    fun `test that weak jobs works correctly`() {
 | 
				
			||||||
 | 
					        val scope = CoroutineScope(Dispatchers.Default)
 | 
				
			||||||
 | 
					        lateinit var weakLaunchJob: Job
 | 
				
			||||||
 | 
					        lateinit var weakAsyncJob: Job
 | 
				
			||||||
 | 
					        scope.launchSynchronously {
 | 
				
			||||||
 | 
					            val completeDeferred = Job()
 | 
				
			||||||
 | 
					            coroutineScope {
 | 
				
			||||||
 | 
					                weakLaunchJob = weakLaunch {
 | 
				
			||||||
 | 
					                    while (isActive) {
 | 
				
			||||||
 | 
					                        delay(100L)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                weakAsyncJob = weakAsync {
 | 
				
			||||||
 | 
					                    while (isActive) {
 | 
				
			||||||
 | 
					                        delay(100L)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                coroutineContext.job.invokeOnCompletion {
 | 
				
			||||||
 | 
					                    scope.launch {
 | 
				
			||||||
 | 
					                        delay(1000L)
 | 
				
			||||||
 | 
					                        completeDeferred.complete()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                launch { delay(1000L); cancel() }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            completeDeferred.join()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert(!weakLaunchJob.isActive)
 | 
				
			||||||
 | 
					        assert(!weakAsyncJob.isActive)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,14 +6,14 @@ kotlin.incremental.js=true
 | 
				
			|||||||
android.useAndroidX=true
 | 
					android.useAndroidX=true
 | 
				
			||||||
android.enableJetifier=true
 | 
					android.enableJetifier=true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
kotlin_version=1.4.30
 | 
					kotlin_version=1.4.32
 | 
				
			||||||
kotlin_coroutines_version=1.4.2
 | 
					kotlin_coroutines_version=1.4.3
 | 
				
			||||||
kotlin_serialisation_core_version=1.1.0
 | 
					kotlin_serialisation_core_version=1.1.0
 | 
				
			||||||
kotlin_exposed_version=0.29.1
 | 
					kotlin_exposed_version=0.30.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ktor_version=1.5.1
 | 
					ktor_version=1.5.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
klockVersion=2.0.6
 | 
					klockVersion=2.0.7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
github_release_plugin_version=2.2.12
 | 
					github_release_plugin_version=2.2.12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,10 +39,10 @@ crypto_js_version=4.0.0
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Dokka
 | 
					# Dokka
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dokka_version=1.4.20
 | 
					dokka_version=1.4.30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Project data
 | 
					# Project data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group=dev.inmo
 | 
					group=dev.inmo
 | 
				
			||||||
version=0.4.27
 | 
					version=0.4.33
 | 
				
			||||||
android_code_version=31
 | 
					android_code_version=37
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
distributionBase=GRADLE_USER_HOME
 | 
					distributionBase=GRADLE_USER_HOME
 | 
				
			||||||
distributionPath=wrapper/dists
 | 
					distributionPath=wrapper/dists
 | 
				
			||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip
 | 
					distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
 | 
				
			||||||
zipStoreBase=GRADLE_USER_HOME
 | 
					zipStoreBase=GRADLE_USER_HOME
 | 
				
			||||||
zipStorePath=wrapper/dists
 | 
					zipStorePath=wrapper/dists
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,22 @@ data class PaginationResult<T>(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fun <T> emptyPaginationResult() = PaginationResult<T>(0, 0, emptyList(), 0)
 | 
					fun <T> emptyPaginationResult() = PaginationResult<T>(0, 0, emptyList(), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @return New [PaginationResult] with [data] without checking of data sizes equality
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun <I, O> PaginationResult<I>.changeResultsUnchecked(
 | 
				
			||||||
 | 
					    data: List<O>
 | 
				
			||||||
 | 
					): PaginationResult<O> = PaginationResult(page, pagesNumber, data, size)
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @return New [PaginationResult] with [data] <b>with</b> checking of data sizes equality
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun <I, O> PaginationResult<I>.changeResults(
 | 
				
			||||||
 | 
					    data: List<O>
 | 
				
			||||||
 | 
					): PaginationResult<O> {
 | 
				
			||||||
 | 
					    require(data.size == results.size)
 | 
				
			||||||
 | 
					    return changeResultsUnchecked(data)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <T> List<T>.createPaginationResult(
 | 
					fun <T> List<T>.createPaginationResult(
 | 
				
			||||||
    pagination: Pagination,
 | 
					    pagination: Pagination,
 | 
				
			||||||
    commonObjectsNumber: Long
 | 
					    commonObjectsNumber: Long
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,14 +7,17 @@ const val defaultMediumPageSize = 5
 | 
				
			|||||||
const val defaultLargePageSize = 10
 | 
					const val defaultLargePageSize = 10
 | 
				
			||||||
const val defaultExtraLargePageSize = 15
 | 
					const val defaultExtraLargePageSize = 15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var defaultPaginationPageSize = defaultMediumPageSize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Suppress("NOTHING_TO_INLINE", "FunctionName")
 | 
					@Suppress("NOTHING_TO_INLINE", "FunctionName")
 | 
				
			||||||
inline fun FirstPagePagination(size: Int = defaultMediumPageSize) =
 | 
					inline fun FirstPagePagination(size: Int = defaultPaginationPageSize) =
 | 
				
			||||||
    SimplePagination(
 | 
					    SimplePagination(
 | 
				
			||||||
        page = 0,
 | 
					        page = 0,
 | 
				
			||||||
        size = size
 | 
					        size = size
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val emptyPagination = Pagination(0, 0)
 | 
					val emptyPagination = Pagination(0, 0)
 | 
				
			||||||
 | 
					val firstPageWithOneElementPagination = FirstPagePagination(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Suppress("NOTHING_TO_INLINE")
 | 
					@Suppress("NOTHING_TO_INLINE")
 | 
				
			||||||
inline fun Pagination.nextPage() =
 | 
					inline fun Pagination.nextPage() =
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,8 +21,10 @@ inline fun PaginationResult<*>.nextPageIfNotEmpty() = if (results.isNotEmpty())
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Suppress("NOTHING_TO_INLINE")
 | 
					@Suppress("NOTHING_TO_INLINE")
 | 
				
			||||||
inline fun PaginationResult<*>.thisPageIfNotEmpty(): Pagination? = if (results.isNotEmpty()) {
 | 
					inline fun <T> PaginationResult<T>.thisPageIfNotEmpty(): PaginationResult<T>? = if (results.isNotEmpty()) {
 | 
				
			||||||
    this
 | 
					    this
 | 
				
			||||||
} else {
 | 
					} else {
 | 
				
			||||||
    null
 | 
					    null
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <T> PaginationResult<T>.currentPageIfNotEmpty() = thisPageIfNotEmpty()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.pagination.utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend fun <T> doForAll(
 | 
				
			||||||
 | 
					    initialPagination: Pagination = FirstPagePagination(),
 | 
				
			||||||
 | 
					    paginationMapper: (PaginationResult<T>) -> Pagination?,
 | 
				
			||||||
 | 
					    block: suspend (Pagination) -> PaginationResult<T>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    doWithPagination(initialPagination) {
 | 
				
			||||||
 | 
					        block(it).let(paginationMapper)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend fun <T> doForAllWithNextPaging(
 | 
				
			||||||
 | 
					    initialPagination: Pagination = FirstPagePagination(),
 | 
				
			||||||
 | 
					    block: suspend (Pagination) -> PaginationResult<T>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    doForAll(
 | 
				
			||||||
 | 
					        initialPagination,
 | 
				
			||||||
 | 
					        { it.nextPageIfNotEmpty() },
 | 
				
			||||||
 | 
					        block
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend fun <T> doAllWithCurrentPaging(
 | 
				
			||||||
 | 
					    initialPagination: Pagination = FirstPagePagination(),
 | 
				
			||||||
 | 
					    block: suspend (Pagination) -> PaginationResult<T>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    doForAll(
 | 
				
			||||||
 | 
					        initialPagination,
 | 
				
			||||||
 | 
					        { it.currentPageIfNotEmpty() },
 | 
				
			||||||
 | 
					        block
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.pagination.utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend fun <T> getAll(
 | 
				
			||||||
 | 
					    initialPagination: Pagination = FirstPagePagination(),
 | 
				
			||||||
 | 
					    paginationMapper: (PaginationResult<T>) -> Pagination?,
 | 
				
			||||||
 | 
					    block: suspend (Pagination) -> PaginationResult<T>
 | 
				
			||||||
 | 
					): List<T> {
 | 
				
			||||||
 | 
					    val results = mutableListOf<T>()
 | 
				
			||||||
 | 
					    doForAll(initialPagination, paginationMapper) {
 | 
				
			||||||
 | 
					        block(it).also {
 | 
				
			||||||
 | 
					            results.addAll(it.results)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return results.toList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend fun <T> getAllWithNextPaging(
 | 
				
			||||||
 | 
					    initialPagination: Pagination = FirstPagePagination(),
 | 
				
			||||||
 | 
					    block: suspend (Pagination) -> PaginationResult<T>
 | 
				
			||||||
 | 
					): List<T> = getAll(
 | 
				
			||||||
 | 
					    initialPagination,
 | 
				
			||||||
 | 
					    { it.nextPageIfNotEmpty() },
 | 
				
			||||||
 | 
					    block
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend fun <T> getAllWithCurrentPaging(
 | 
				
			||||||
 | 
					    initialPagination: Pagination = FirstPagePagination(),
 | 
				
			||||||
 | 
					    block: suspend (Pagination) -> PaginationResult<T>
 | 
				
			||||||
 | 
					): List<T> = getAll(
 | 
				
			||||||
 | 
					    initialPagination,
 | 
				
			||||||
 | 
					    { it.currentPageIfNotEmpty() },
 | 
				
			||||||
 | 
					    block
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@@ -36,6 +36,6 @@ class PaginatedIterable<T>(
 | 
				
			|||||||
@Suppress("NOTHING_TO_INLINE")
 | 
					@Suppress("NOTHING_TO_INLINE")
 | 
				
			||||||
inline fun <T> makeIterable(
 | 
					inline fun <T> makeIterable(
 | 
				
			||||||
    noinline countGetter: () -> Long,
 | 
					    noinline countGetter: () -> Long,
 | 
				
			||||||
    pageSize: Int = defaultMediumPageSize,
 | 
					    pageSize: Int = defaultPaginationPageSize,
 | 
				
			||||||
    noinline paginationResultGetter: Pagination.() -> PaginationResult<T>
 | 
					    noinline paginationResultGetter: Pagination.() -> PaginationResult<T>
 | 
				
			||||||
): Iterable<T> = PaginatedIterable(pageSize, countGetter, paginationResultGetter)
 | 
					): Iterable<T> = PaginatedIterable(pageSize, countGetter, paginationResultGetter)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,6 @@ val Pagination.asUrlQueryArrayParts
 | 
				
			|||||||
val Map<String, String?>.extractPagination: Pagination
 | 
					val Map<String, String?>.extractPagination: Pagination
 | 
				
			||||||
    get() = SimplePagination(
 | 
					    get() = SimplePagination(
 | 
				
			||||||
        get(paginationPageKey) ?.toIntOrNull() ?: 0,
 | 
					        get(paginationPageKey) ?.toIntOrNull() ?: 0,
 | 
				
			||||||
        get(paginationSizeKey) ?.toIntOrNull() ?: defaultMediumPageSize
 | 
					        get(paginationSizeKey) ?.toIntOrNull() ?: defaultPaginationPageSize
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ import io.ktor.http.Parameters
 | 
				
			|||||||
val Parameters.extractPagination: Pagination
 | 
					val Parameters.extractPagination: Pagination
 | 
				
			||||||
    get() = SimplePagination(
 | 
					    get() = SimplePagination(
 | 
				
			||||||
        get("page") ?.toIntOrNull() ?: 0,
 | 
					        get("page") ?.toIntOrNull() ?: 0,
 | 
				
			||||||
        get("size") ?.toIntOrNull() ?: defaultMediumPageSize
 | 
					        get("size") ?.toIntOrNull() ?: defaultPaginationPageSize
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val ApplicationCall.extractPagination: Pagination
 | 
					val ApplicationCall.extractPagination: Pagination
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
{"bintrayConfig":{"repo":"MicroUtils","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/MicroUtils","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror/src/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror","vcsUrl":"ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git","includeGpgSigning":true,"publishToMavenCentral":true,"developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}]}}
 | 
					 | 
				
			||||||
@@ -12,11 +12,11 @@ publishing {
 | 
				
			|||||||
        pom {
 | 
					        pom {
 | 
				
			||||||
            description = "It is set of projects with micro tools for avoiding of routines coding"
 | 
					            description = "It is set of projects with micro tools for avoiding of routines coding"
 | 
				
			||||||
            name = "${project.name}"
 | 
					            name = "${project.name}"
 | 
				
			||||||
            url = "https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror"
 | 
					            url = "https://github.com/InsanusMokrassar/MicroUtils/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            scm {
 | 
					            scm {
 | 
				
			||||||
                developerConnection = "scm:git:[fetch=]ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git[push=]ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git"
 | 
					                developerConnection = "scm:git:[fetch=]https://github.com/InsanusMokrassar/MicroUtils.git[push=]https://github.com/InsanusMokrassar/MicroUtils.git"
 | 
				
			||||||
                url = "ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git"
 | 
					                url = "https://github.com/InsanusMokrassar/MicroUtils.git"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            developers {
 | 
					            developers {
 | 
				
			||||||
@@ -40,22 +40,23 @@ publishing {
 | 
				
			|||||||
                
 | 
					                
 | 
				
			||||||
                    license {
 | 
					                    license {
 | 
				
			||||||
                        name = "Apache Software License 2.0"
 | 
					                        name = "Apache Software License 2.0"
 | 
				
			||||||
                        url = "https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror/src/master/LICENSE"
 | 
					                        url = "https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        repositories {
 | 
					        repositories {
 | 
				
			||||||
 | 
					            if ((project.hasProperty('GITHUBPACKAGES_USER') || System.getenv('GITHUBPACKAGES_USER') != null) && (project.hasProperty('GITHUBPACKAGES_PASSWORD') || System.getenv('GITHUBPACKAGES_PASSWORD') != null)) {
 | 
				
			||||||
                maven {
 | 
					                maven {
 | 
				
			||||||
                name = "bintray"
 | 
					                    name = "GithubPackages"
 | 
				
			||||||
                url = uri("https://api.bintray.com/maven/${project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')}/MicroUtils/${project.name}/;publish=1;override=1")
 | 
					                    url = uri("https://maven.pkg.github.com/InsanusMokrassar/MicroUtils")
 | 
				
			||||||
                    credentials {
 | 
					                    credentials {
 | 
				
			||||||
                    username = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
 | 
					                        username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
 | 
				
			||||||
                    password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
 | 
					                        password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            
 | 
					            }
 | 
				
			||||||
 | 
					            if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
 | 
				
			||||||
                maven {
 | 
					                maven {
 | 
				
			||||||
                    name = "sonatype"
 | 
					                    name = "sonatype"
 | 
				
			||||||
                    url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
 | 
					                    url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
 | 
				
			||||||
@@ -64,9 +65,8 @@ publishing {
 | 
				
			|||||||
                        password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
 | 
					                        password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								publish.kpsb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								publish.kpsb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","includeGpgSigning":true,"developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}]}}
 | 
				
			||||||
							
								
								
									
										18
									
								
								repos/cache/build.gradle
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								repos/cache/build.gradle
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.multiplatform"
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.plugin.serialization"
 | 
				
			||||||
 | 
					    id "com.android.library"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					apply from: "$mppProjectWithSerializationPresetPath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					kotlin {
 | 
				
			||||||
 | 
					    sourceSets {
 | 
				
			||||||
 | 
					        commonMain {
 | 
				
			||||||
 | 
					            dependencies {
 | 
				
			||||||
 | 
					                api internalProject("micro_utils.repos.common")
 | 
				
			||||||
 | 
					                api internalProject("micro_utils.repos.inmemory")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CRUDCacheRepo.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CRUDCacheRepo.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.launchIn
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.onEach
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
 | 
					    protected val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
 | 
				
			||||||
 | 
					    protected val kvCache: KVCache<IdType, ObjectType>,
 | 
				
			||||||
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
 | 
					    protected val idGetter: (ObjectType) -> IdType
 | 
				
			||||||
 | 
					) : CRUDRepo<ObjectType, IdType, InputValueType> by parentRepo {
 | 
				
			||||||
 | 
					    protected val onNewJob = parentRepo.newObjectsFlow.onEach { kvCache.set(idGetter(it), it) }.launchIn(scope)
 | 
				
			||||||
 | 
					    protected val onUpdatedJob = parentRepo.updatedObjectsFlow.onEach { kvCache.set(idGetter(it), it) }.launchIn(scope)
 | 
				
			||||||
 | 
					    protected val onRemoveJob = parentRepo.deletedObjectsIdsFlow.onEach { kvCache.unset(it) }.launchIn(scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun getById(id: IdType): ObjectType? = kvCache.get(id) ?: (parentRepo.getById(id) ?.also {
 | 
				
			||||||
 | 
					        kvCache.set(id, it)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										41
									
								
								repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KVCache.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KVCache.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
 | 
				
			||||||
 | 
					import kotlinx.coroutines.sync.Mutex
 | 
				
			||||||
 | 
					import kotlinx.coroutines.sync.withLock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface KVCache<K, V> : KeyValueRepo<K, V>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					open class SimpleKVCache<K, V>(
 | 
				
			||||||
 | 
					    protected val cachedValuesCount: Int,
 | 
				
			||||||
 | 
					    private val kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
 | 
				
			||||||
 | 
					) : KVCache<K, V>, KeyValueRepo<K, V> by kvParent {
 | 
				
			||||||
 | 
					    protected open val cacheStack = ArrayList<K>(cachedValuesCount)
 | 
				
			||||||
 | 
					    protected val syncMutex = Mutex()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected suspend fun makeUnset(toUnset: List<K>) {
 | 
				
			||||||
 | 
					        cacheStack.removeAll(toUnset)
 | 
				
			||||||
 | 
					        kvParent.unset(toUnset)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun set(toSet: Map<K, V>) {
 | 
				
			||||||
 | 
					        syncMutex.withLock {
 | 
				
			||||||
 | 
					            if (toSet.size > cachedValuesCount) {
 | 
				
			||||||
 | 
					                cacheStack.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                kvParent.unset(getAllWithNextPaging { kvParent.keys(it) })
 | 
				
			||||||
 | 
					                val keysToInclude = toSet.keys.drop(toSet.size - cachedValuesCount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                cacheStack.addAll(keysToInclude)
 | 
				
			||||||
 | 
					                kvParent.set(keysToInclude.associateWith { toSet.getValue(it) })
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                makeUnset(cacheStack.take(toSet.size))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun unset(toUnset: List<K>) {
 | 
				
			||||||
 | 
					        syncMutex.withLock { makeUnset(toUnset) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValueCacheRepo.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValueCacheRepo.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.*
 | 
				
			||||||
 | 
					import kotlinx.coroutines.sync.Mutex
 | 
				
			||||||
 | 
					import kotlinx.coroutines.sync.withLock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					open class KeyValueCacheRepo<Key,Value>(
 | 
				
			||||||
 | 
					    protected val parentRepo: KeyValueRepo<Key, Value>,
 | 
				
			||||||
 | 
					    protected val kvCache: KVCache<Key, Value>,
 | 
				
			||||||
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
				
			||||||
 | 
					) : KeyValueRepo<Key,Value> by parentRepo {
 | 
				
			||||||
 | 
					    protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope)
 | 
				
			||||||
 | 
					    protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun get(k: Key): Value? = kvCache.get(k) ?: parentRepo.get(k) ?.also { kvCache.set(k, it) }
 | 
				
			||||||
 | 
					    override suspend fun contains(key: Key): Boolean = kvCache.contains(key) || parentRepo.contains(key)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										37
									
								
								repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValuesCacheRepo.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValuesCacheRepo.kt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.Pagination
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.utils.paginate
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.utils.reverse
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.*
 | 
				
			||||||
 | 
					import kotlinx.coroutines.sync.Mutex
 | 
				
			||||||
 | 
					import kotlinx.coroutines.sync.withLock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					open class KeyValuesCacheRepo<Key,Value>(
 | 
				
			||||||
 | 
					    protected val parentRepo: KeyValuesRepo<Key, Value>,
 | 
				
			||||||
 | 
					    protected val kvCache: KVCache<Key, List<Value>>,
 | 
				
			||||||
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
				
			||||||
 | 
					) : KeyValuesRepo<Key,Value> by parentRepo {
 | 
				
			||||||
 | 
					    protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, kvCache.get(it.first) ?.plus(it.second) ?: listOf(it.second)) }.launchIn(scope)
 | 
				
			||||||
 | 
					    protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.set(it.first, kvCache.get(it.first) ?.minus(it.second) ?: return@onEach) }.launchIn(scope)
 | 
				
			||||||
 | 
					    protected val onDataClearedJob = parentRepo.onDataCleared.onEach { kvCache.unset(it) }.launchIn(scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
 | 
				
			||||||
 | 
					        return kvCache.get(k) ?.paginate(
 | 
				
			||||||
 | 
					            pagination.let { if (reversed) it.reverse(count(k)) else it }
 | 
				
			||||||
 | 
					        ) ?.let {
 | 
				
			||||||
 | 
					            if (reversed) it.copy(results = it.results.reversed()) else it
 | 
				
			||||||
 | 
					        } ?: parentRepo.get(k, pagination, reversed)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    override suspend fun getAll(k: Key, reversed: Boolean): List<Value> {
 | 
				
			||||||
 | 
					        return kvCache.get(k) ?.let {
 | 
				
			||||||
 | 
					            if (reversed) it.reversed() else it
 | 
				
			||||||
 | 
					        } ?: parentRepo.getAll(k, reversed)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    override suspend fun contains(k: Key, v: Value): Boolean = kvCache.get(k) ?.contains(v) ?: parentRepo.contains(k, v)
 | 
				
			||||||
 | 
					    override suspend fun contains(k: Key): Boolean = kvCache.contains(k) || parentRepo.contains(k)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								repos/cache/src/main/AndroidManifest.xml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								repos/cache/src/main/AndroidManifest.xml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<manifest package="dev.inmo.micro_utils.repos.cache"/>
 | 
				
			||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos
 | 
					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.getAllWithNextPaging
 | 
				
			||||||
import kotlinx.coroutines.flow.Flow
 | 
					import kotlinx.coroutines.flow.Flow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface ReadOneToManyKeyValueRepo<Key, Value> : Repo {
 | 
					interface ReadOneToManyKeyValueRepo<Key, Value> : Repo {
 | 
				
			||||||
@@ -12,14 +13,12 @@ interface ReadOneToManyKeyValueRepo<Key, Value> : Repo {
 | 
				
			|||||||
    suspend fun count(k: Key): Long
 | 
					    suspend fun count(k: Key): Long
 | 
				
			||||||
    suspend fun count(): Long
 | 
					    suspend fun count(): Long
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    suspend fun getAll(k: Key, reversed: Boolean = false): List<Value> = mutableListOf<Value>().also { list ->
 | 
					    suspend fun getAll(k: Key, reversed: Boolean = false): List<Value> {
 | 
				
			||||||
        doWithPagination {
 | 
					        val results = getAllWithNextPaging { get(k, it) }
 | 
				
			||||||
            get(k, it).also {
 | 
					        return if (reversed) {
 | 
				
			||||||
                list.addAll(it.results)
 | 
					            results.reversed()
 | 
				
			||||||
            }.nextPageIfNotEmpty()
 | 
					        } else {
 | 
				
			||||||
        }
 | 
					            results
 | 
				
			||||||
        if (reversed) {
 | 
					 | 
				
			||||||
            list.reverse()
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos
 | 
					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 kotlinx.coroutines.flow.Flow
 | 
					import kotlinx.coroutines.flow.Flow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface ReadStandardKeyValueRepo<Key, Value> : Repo {
 | 
					interface ReadStandardKeyValueRepo<Key, Value> : Repo {
 | 
				
			||||||
@@ -41,7 +42,7 @@ suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.unsetWithV
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value>, WriteStandardKeyValueRepo<Key, Value> {
 | 
					interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value>, WriteStandardKeyValueRepo<Key, Value> {
 | 
				
			||||||
    override suspend fun unsetWithValues(toUnset: List<Value>) = toUnset.forEach { v ->
 | 
					    override suspend fun unsetWithValues(toUnset: List<Value>) = toUnset.forEach { v ->
 | 
				
			||||||
        doWithPagination {
 | 
					        doAllWithCurrentPaging {
 | 
				
			||||||
            keys(v, it).also {
 | 
					            keys(v, it).also {
 | 
				
			||||||
                unset(it.results)
 | 
					                unset(it.results)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,31 +1,33 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.pagination
 | 
					package dev.inmo.micro_utils.repos.pagination
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.*
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
 | 
					import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("Will be removed soon due to redundancy. Can be replaced with other doForAll extensions")
 | 
				
			||||||
suspend inline fun <T, ID, REPO : ReadStandardCRUDRepo<T, ID>> REPO.doForAll(
 | 
					suspend inline fun <T, ID, REPO : ReadStandardCRUDRepo<T, ID>> REPO.doForAll(
 | 
				
			||||||
    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
					    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
				
			||||||
    methodCaller: suspend REPO.(Pagination) -> PaginationResult<T>,
 | 
					    crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<T>,
 | 
				
			||||||
    block: (List<T>) -> Unit
 | 
					    crossinline block: (List<T>) -> Unit
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    doWithPagination {
 | 
					    doForAllWithNextPaging {
 | 
				
			||||||
        methodCaller(it).also {
 | 
					        methodCaller(it).also {
 | 
				
			||||||
            block(it.results)
 | 
					            block(it.results)
 | 
				
			||||||
        }.nextPageIfNotEmpty()
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("Will be removed soon due to redundancy. Can be replaced with other doForAll extensions")
 | 
				
			||||||
suspend inline fun <T, ID, REPO : ReadStandardCRUDRepo<T, ID>> REPO.doForAll(
 | 
					suspend inline fun <T, ID, REPO : ReadStandardCRUDRepo<T, ID>> REPO.doForAll(
 | 
				
			||||||
    block: (List<T>) -> Unit
 | 
					    crossinline block: (List<T>) -> Unit
 | 
				
			||||||
) = doForAll({ getByPagination(it) }, block)
 | 
					) = doForAllWithNextPaging {
 | 
				
			||||||
 | 
					    getByPagination(it).also { block(it.results) }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <T, ID, REPO : ReadStandardCRUDRepo<T, ID>> REPO.getAll(
 | 
					suspend inline fun <T, ID, REPO : ReadStandardCRUDRepo<T, ID>> REPO.getAll(
 | 
				
			||||||
    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
					    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
				
			||||||
    methodCaller: suspend REPO.(Pagination) -> PaginationResult<T>
 | 
					    crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<T>
 | 
				
			||||||
): List<T> {
 | 
					): List<T> = getAllWithNextPaging {
 | 
				
			||||||
    val resultList = mutableListOf<T>()
 | 
					    methodCaller(this, it)
 | 
				
			||||||
    doForAll(methodCaller) {
 | 
					 | 
				
			||||||
        resultList.addAll(it)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return resultList
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,10 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.pagination
 | 
					package dev.inmo.micro_utils.repos.pagination
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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.repos.ReadStandardKeyValueRepo
 | 
					import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("Will be removed soon due to redundancy")
 | 
				
			||||||
suspend inline fun <Key, Value, REPO : ReadStandardKeyValueRepo<Key, Value>> REPO.doForAll(
 | 
					suspend inline fun <Key, Value, REPO : ReadStandardKeyValueRepo<Key, Value>> REPO.doForAll(
 | 
				
			||||||
    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
					    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
				
			||||||
    methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>,
 | 
					    methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>,
 | 
				
			||||||
@@ -15,17 +17,17 @@ suspend inline fun <Key, Value, REPO : ReadStandardKeyValueRepo<Key, Value>> REP
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("Will be removed soon due to redundancy")
 | 
				
			||||||
suspend inline fun <Key, Value, REPO : ReadStandardKeyValueRepo<Key, Value>> REPO.doForAll(
 | 
					suspend inline fun <Key, Value, REPO : ReadStandardKeyValueRepo<Key, Value>> REPO.doForAll(
 | 
				
			||||||
    block: (List<Pair<Key, Value>>) -> Unit
 | 
					    block: (List<Pair<Key, Value>>) -> Unit
 | 
				
			||||||
) = doForAll({ keys(it, false) }, block)
 | 
					) = doForAll({ keys(it, false) }, block)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <Key, Value, REPO : ReadStandardKeyValueRepo<Key, Value>> REPO.getAll(
 | 
					suspend inline fun <Key, Value, REPO : ReadStandardKeyValueRepo<Key, Value>> REPO.getAll(
 | 
				
			||||||
    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
					    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
				
			||||||
    methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
 | 
					    crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
 | 
				
			||||||
): List<Pair<Key, Value>> {
 | 
					): List<Pair<Key, Value>> = getAllWithNextPaging {
 | 
				
			||||||
    val resultList = mutableListOf<Pair<Key, Value>>()
 | 
					    val result = methodCaller(it)
 | 
				
			||||||
    doForAll(methodCaller) {
 | 
					    result.changeResultsUnchecked(
 | 
				
			||||||
        resultList.addAll(it)
 | 
					        result.results.mapNotNull { it to (get(it) ?: return@mapNotNull null) }
 | 
				
			||||||
    }
 | 
					    )
 | 
				
			||||||
    return resultList
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,10 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.pagination
 | 
					package dev.inmo.micro_utils.repos.pagination
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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.repos.ReadOneToManyKeyValueRepo
 | 
					import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("Will be removed soon due to redundancy")
 | 
				
			||||||
suspend inline fun <Key, Value, REPO : ReadOneToManyKeyValueRepo<Key, Value>> REPO.doForAll(
 | 
					suspend inline fun <Key, Value, REPO : ReadOneToManyKeyValueRepo<Key, Value>> REPO.doForAll(
 | 
				
			||||||
    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
					    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
				
			||||||
    methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>,
 | 
					    methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>,
 | 
				
			||||||
@@ -25,17 +27,19 @@ suspend inline fun <Key, Value, REPO : ReadOneToManyKeyValueRepo<Key, Value>> RE
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("Will be removed soon due to redundancy")
 | 
				
			||||||
suspend inline fun <Key, Value, REPO : ReadOneToManyKeyValueRepo<Key, Value>> REPO.doForAll(
 | 
					suspend inline fun <Key, Value, REPO : ReadOneToManyKeyValueRepo<Key, Value>> REPO.doForAll(
 | 
				
			||||||
    block: (List<Pair<Key, List<Value>>>) -> Unit
 | 
					    block: (List<Pair<Key, List<Value>>>) -> Unit
 | 
				
			||||||
) = doForAll({ keys(it, false) }, block)
 | 
					) = doForAll({ keys(it, false) }, block)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <Key, Value, REPO : ReadOneToManyKeyValueRepo<Key, Value>> REPO.getAll(
 | 
					suspend inline fun <Key, Value, REPO : ReadOneToManyKeyValueRepo<Key, Value>> REPO.getAll(
 | 
				
			||||||
    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
					    @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
 | 
				
			||||||
    methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
 | 
					    crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
 | 
				
			||||||
): List<Pair<Key, List<Value>>> {
 | 
					): List<Pair<Key, List<Value>>> = getAllWithNextPaging {
 | 
				
			||||||
    val resultList = mutableListOf<Pair<Key, List<Value>>>()
 | 
					    val keysResult = methodCaller(it)
 | 
				
			||||||
    doForAll(methodCaller) {
 | 
					    keysResult.changeResultsUnchecked(
 | 
				
			||||||
        resultList.addAll(it)
 | 
					        keysResult.results.map { k ->
 | 
				
			||||||
 | 
					            k to getAll(k)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    return resultList
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,20 +26,39 @@ fun SQLiteDatabase.createTable(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun Cursor.getString(columnName: String) = getString(
 | 
					/**
 | 
				
			||||||
    getColumnIndex(columnName)
 | 
					 * @throws IllegalArgumentException
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun Cursor.getString(columnName: String): String = getString(
 | 
				
			||||||
 | 
					    getColumnIndexOrThrow(columnName)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun Cursor.getLong(columnName: String) = getLong(
 | 
					/**
 | 
				
			||||||
    getColumnIndex(columnName)
 | 
					 * @throws IllegalArgumentException
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun Cursor.getShort(columnName: String): Short = getShort(
 | 
				
			||||||
 | 
					    getColumnIndexOrThrow(columnName)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun Cursor.getInt(columnName: String) = getInt(
 | 
					/**
 | 
				
			||||||
    getColumnIndex(columnName)
 | 
					 * @throws IllegalArgumentException
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun Cursor.getLong(columnName: String): Long = getLong(
 | 
				
			||||||
 | 
					    getColumnIndexOrThrow(columnName)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun Cursor.getDouble(columnName: String) = getDouble(
 | 
					/**
 | 
				
			||||||
    getColumnIndex(columnName)
 | 
					 * @throws IllegalArgumentException
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun Cursor.getInt(columnName: String): Int = getInt(
 | 
				
			||||||
 | 
					    getColumnIndexOrThrow(columnName)
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @throws IllegalArgumentException
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun Cursor.getDouble(columnName: String): Double = getDouble(
 | 
				
			||||||
 | 
					    getColumnIndexOrThrow(columnName)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun SQLiteDatabase.select(
 | 
					fun SQLiteDatabase.select(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,9 @@ private object ContextsPool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    suspend fun <T> use(block: suspend (CoroutineContext) -> T): T = acquireContext().let {
 | 
					    suspend fun <T> use(block: suspend (CoroutineContext) -> T): T = acquireContext().let {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
 | 
					            safely {
 | 
				
			||||||
                block(it)
 | 
					                block(it)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        } finally {
 | 
					        } finally {
 | 
				
			||||||
            freeContext(it)
 | 
					            freeContext(it)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -48,11 +50,12 @@ class TransactionContext(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend fun <T> SQLiteDatabase.transaction(block: suspend SQLiteDatabase.() -> T): T {
 | 
					suspend fun <T> SQLiteDatabase.transaction(block: suspend SQLiteDatabase.() -> T): T {
 | 
				
			||||||
    return coroutineContext[TransactionContext] ?.let {
 | 
					    coroutineContext[TransactionContext] ?.let {
 | 
				
			||||||
        withContext(it.databaseContext) {
 | 
					        return withContext(it.databaseContext) {
 | 
				
			||||||
            block()
 | 
					            block()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } ?: ContextsPool.use { context ->
 | 
					    }
 | 
				
			||||||
 | 
					    return ContextsPool.use { context ->
 | 
				
			||||||
        withContext(TransactionContext(context) + context) {
 | 
					        withContext(TransactionContext(context) + context) {
 | 
				
			||||||
            beginTransaction()
 | 
					            beginTransaction()
 | 
				
			||||||
            safely(
 | 
					            safely(
 | 
				
			||||||
@@ -70,18 +73,18 @@ suspend fun <T> SQLiteDatabase.transaction(block: suspend SQLiteDatabase.() -> T
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline fun <T> SQLiteDatabase.inlineTransaction(block: SQLiteDatabase.() -> T): T {
 | 
					inline fun <T> SQLiteDatabase.inlineTransaction(crossinline block: SQLiteDatabase.() -> T): T {
 | 
				
			||||||
    return when {
 | 
					    return when {
 | 
				
			||||||
        inTransaction() -> block()
 | 
					        inTransaction() -> block()
 | 
				
			||||||
        else -> {
 | 
					        else -> {
 | 
				
			||||||
            beginTransaction()
 | 
					            beginTransaction()
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                block().also {
 | 
					                block().also { setTransactionSuccessful() }
 | 
				
			||||||
                    setTransactionSuccessful()
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } finally {
 | 
					            } finally {
 | 
				
			||||||
                endTransaction()
 | 
					                endTransaction()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun <T> SQLiteDatabase.blockingTransaction(block: SQLiteDatabase.() -> T): T = inlineTransaction(block)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,20 @@ class StandardSQLHelper(
 | 
				
			|||||||
    suspend fun <T> readableTransaction(block: suspend SQLiteDatabase.() -> T): T = sqlOpenHelper.readableTransaction(block)
 | 
					    suspend fun <T> readableTransaction(block: suspend SQLiteDatabase.() -> T): T = sqlOpenHelper.readableTransaction(block)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun <T> SQLiteOpenHelper.blockingWritableTransaction(block: SQLiteDatabase.() -> T): T {
 | 
				
			||||||
 | 
					    return writableDatabase.blockingTransaction(block)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					fun <T> SQLiteOpenHelper.blockingReadableTransaction(block: SQLiteDatabase.() -> T): T {
 | 
				
			||||||
 | 
					    return readableDatabase.blockingTransaction(block)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun <T> StandardSQLHelper.blockingWritableTransaction(block: SQLiteDatabase.() -> T): T {
 | 
				
			||||||
 | 
					    return sqlOpenHelper.blockingWritableTransaction(block)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					fun <T> StandardSQLHelper.blockingReadableTransaction(block: SQLiteDatabase.() -> T): T {
 | 
				
			||||||
 | 
					    return sqlOpenHelper.blockingReadableTransaction(block)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend fun <T> SQLiteOpenHelper.writableTransaction(block: suspend SQLiteDatabase.() -> T): T {
 | 
					suspend fun <T> SQLiteOpenHelper.writableTransaction(block: suspend SQLiteDatabase.() -> T): T {
 | 
				
			||||||
    return writableDatabase.transaction(block)
 | 
					    return writableDatabase.transaction(block)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ abstract class AbstractAndroidCRUDRepo<ObjectType, IdType>(
 | 
				
			|||||||
        it.count
 | 
					        it.count
 | 
				
			||||||
    }.toLong()
 | 
					    }.toLong()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(id: IdType): Boolean = helper.readableTransaction {
 | 
					    override suspend fun contains(id: IdType): Boolean = helper.blockingReadableTransaction {
 | 
				
			||||||
        select(
 | 
					        select(
 | 
				
			||||||
            tableName,
 | 
					            tableName,
 | 
				
			||||||
            null,
 | 
					            null,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,9 +19,10 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
 | 
				
			|||||||
    protected abstract suspend fun InputValueType.asContentValues(id: IdType? = null): ContentValues
 | 
					    protected abstract suspend fun InputValueType.asContentValues(id: IdType? = null): ContentValues
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun create(values: List<InputValueType>): List<ObjectType> {
 | 
					    override suspend fun create(values: List<InputValueType>): List<ObjectType> {
 | 
				
			||||||
        val indexes = helper.writableTransaction {
 | 
					        val valuesContentValues = values.map { it.asContentValues() }
 | 
				
			||||||
            values.map {
 | 
					        val indexes = helper.blockingWritableTransaction {
 | 
				
			||||||
                insert(tableName, null, it.asContentValues())
 | 
					            valuesContentValues.map {
 | 
				
			||||||
 | 
					                insert(tableName, null, it)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return helper.readableTransaction {
 | 
					        return helper.readableTransaction {
 | 
				
			||||||
@@ -47,7 +48,7 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    override suspend fun deleteById(ids: List<IdType>) {
 | 
					    override suspend fun deleteById(ids: List<IdType>) {
 | 
				
			||||||
        val deleted = mutableListOf<IdType>()
 | 
					        val deleted = mutableListOf<IdType>()
 | 
				
			||||||
        helper.writableTransaction {
 | 
					        helper.blockingWritableTransaction {
 | 
				
			||||||
            ids.forEach { id ->
 | 
					            ids.forEach { id ->
 | 
				
			||||||
                delete(tableName, "$idColumnName=?", arrayOf(id.asId)).also {
 | 
					                delete(tableName, "$idColumnName=?", arrayOf(id.asId)).also {
 | 
				
			||||||
                    if (it > 0) {
 | 
					                    if (it > 0) {
 | 
				
			||||||
@@ -64,7 +65,7 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
 | 
				
			|||||||
    override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
 | 
					    override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
 | 
				
			||||||
        val asContentValues = value.asContentValues(id)
 | 
					        val asContentValues = value.asContentValues(id)
 | 
				
			||||||
        if (asContentValues.keySet().isNotEmpty()) {
 | 
					        if (asContentValues.keySet().isNotEmpty()) {
 | 
				
			||||||
            helper.writableTransaction {
 | 
					            helper.blockingWritableTransaction {
 | 
				
			||||||
                update(
 | 
					                update(
 | 
				
			||||||
                    tableName,
 | 
					                    tableName,
 | 
				
			||||||
                    asContentValues,
 | 
					                    asContentValues,
 | 
				
			||||||
@@ -79,11 +80,12 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> {
 | 
					    override suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> {
 | 
				
			||||||
 | 
					        val contentValues = values.map { (id, value) -> id to value.asContentValues(id) }
 | 
				
			||||||
        helper.writableTransaction {
 | 
					        helper.writableTransaction {
 | 
				
			||||||
            values.forEach { (id, value) ->
 | 
					            contentValues.forEach { (id, contentValues) ->
 | 
				
			||||||
                update(
 | 
					                update(
 | 
				
			||||||
                    tableName,
 | 
					                    tableName,
 | 
				
			||||||
                    value.asContentValues(id),
 | 
					                    contentValues,
 | 
				
			||||||
                    "$idColumnName=?",
 | 
					                    "$idColumnName=?",
 | 
				
			||||||
                    arrayOf(id.asId)
 | 
					                    arrayOf(id.asId)
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
@@ -98,5 +100,5 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun count(): Long = helper.readableTransaction { select(tableName).use { it.count.toLong() } }
 | 
					    override suspend fun count(): Long = helper.blockingReadableTransaction { select(tableName).use { it.count.toLong() } }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -42,8 +42,7 @@ class OneToManyAndroidRepo<Key, Value>(
 | 
				
			|||||||
    private fun String.asKey(): Key = internalSerialFormat.decodeFromString(keySerializer, this)
 | 
					    private fun String.asKey(): Key = internalSerialFormat.decodeFromString(keySerializer, this)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        runBlocking(DatabaseCoroutineContext) {
 | 
					        helper.blockingWritableTransaction {
 | 
				
			||||||
            helper.writableTransaction {
 | 
					 | 
				
			||||||
            createTable(
 | 
					            createTable(
 | 
				
			||||||
                tableName,
 | 
					                tableName,
 | 
				
			||||||
                internalId to internalIdType,
 | 
					                internalId to internalIdType,
 | 
				
			||||||
@@ -52,11 +51,10 @@ class OneToManyAndroidRepo<Key, Value>(
 | 
				
			|||||||
            )
 | 
					            )
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun add(toAdd: Map<Key, List<Value>>) {
 | 
					    override suspend fun add(toAdd: Map<Key, List<Value>>) {
 | 
				
			||||||
        val added = mutableListOf<Pair<Key, Value>>()
 | 
					        val added = mutableListOf<Pair<Key, Value>>()
 | 
				
			||||||
        helper.writableTransaction {
 | 
					        helper.blockingWritableTransaction {
 | 
				
			||||||
            toAdd.forEach { (k, values) ->
 | 
					            toAdd.forEach { (k, values) ->
 | 
				
			||||||
                values.forEach { v ->
 | 
					                values.forEach { v ->
 | 
				
			||||||
                    insert(
 | 
					                    insert(
 | 
				
			||||||
@@ -78,7 +76,7 @@ class OneToManyAndroidRepo<Key, Value>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun clear(k: Key) {
 | 
					    override suspend fun clear(k: Key) {
 | 
				
			||||||
        helper.writableTransaction {
 | 
					        helper.blockingWritableTransaction {
 | 
				
			||||||
            delete(tableName, "$idColumnName=?", arrayOf(k.asId()))
 | 
					            delete(tableName, "$idColumnName=?", arrayOf(k.asId()))
 | 
				
			||||||
        }.also {
 | 
					        }.also {
 | 
				
			||||||
            if (it > 0) {
 | 
					            if (it > 0) {
 | 
				
			||||||
@@ -88,7 +86,7 @@ class OneToManyAndroidRepo<Key, Value>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun set(toSet: Map<Key, List<Value>>) {
 | 
					    override suspend fun set(toSet: Map<Key, List<Value>>) {
 | 
				
			||||||
        val (clearedKeys, inserted) = helper.writableTransaction {
 | 
					        val (clearedKeys, inserted) = helper.blockingWritableTransaction {
 | 
				
			||||||
            toSet.mapNotNull { (k, _) ->
 | 
					            toSet.mapNotNull { (k, _) ->
 | 
				
			||||||
                if (delete(tableName, "$idColumnName=?", arrayOf(k.asId())) > 0) {
 | 
					                if (delete(tableName, "$idColumnName=?", arrayOf(k.asId())) > 0) {
 | 
				
			||||||
                    k
 | 
					                    k
 | 
				
			||||||
@@ -110,13 +108,13 @@ class OneToManyAndroidRepo<Key, Value>(
 | 
				
			|||||||
        inserted.forEach { newPair -> _onNewValue.emit(newPair) }
 | 
					        inserted.forEach { newPair -> _onNewValue.emit(newPair) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(k: Key): Boolean = helper.readableTransaction {
 | 
					    override suspend fun contains(k: Key): Boolean = helper.blockingReadableTransaction {
 | 
				
			||||||
        select(tableName, selection = "$idColumnName=?", selectionArgs = arrayOf(k.asId()), limit = FirstPagePagination(1).limitClause()).use {
 | 
					        select(tableName, selection = "$idColumnName=?", selectionArgs = arrayOf(k.asId()), limit = FirstPagePagination(1).limitClause()).use {
 | 
				
			||||||
            it.count > 0
 | 
					            it.count > 0
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(k: Key, v: Value): Boolean = helper.readableTransaction {
 | 
					    override suspend fun contains(k: Key, v: Value): Boolean = helper.blockingReadableTransaction {
 | 
				
			||||||
        select(
 | 
					        select(
 | 
				
			||||||
            tableName,
 | 
					            tableName,
 | 
				
			||||||
            selection = "$idColumnName=? AND $valueColumnName=?",
 | 
					            selection = "$idColumnName=? AND $valueColumnName=?",
 | 
				
			||||||
@@ -127,7 +125,7 @@ class OneToManyAndroidRepo<Key, Value>(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun count(): Long =helper.readableTransaction {
 | 
					    override suspend fun count(): Long =helper.blockingReadableTransaction {
 | 
				
			||||||
        select(
 | 
					        select(
 | 
				
			||||||
            tableName
 | 
					            tableName
 | 
				
			||||||
        ).use {
 | 
					        ).use {
 | 
				
			||||||
@@ -135,7 +133,7 @@ class OneToManyAndroidRepo<Key, Value>(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }.toLong()
 | 
					    }.toLong()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun count(k: Key): Long = helper.readableTransaction {
 | 
					    override suspend fun count(k: Key): Long = helper.blockingReadableTransaction {
 | 
				
			||||||
        select(tableName, selection = "$idColumnName=?", selectionArgs = arrayOf(k.asId()), limit = FirstPagePagination(1).limitClause()).use {
 | 
					        select(tableName, selection = "$idColumnName=?", selectionArgs = arrayOf(k.asId()), limit = FirstPagePagination(1).limitClause()).use {
 | 
				
			||||||
            it.count
 | 
					            it.count
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -147,7 +145,7 @@ class OneToManyAndroidRepo<Key, Value>(
 | 
				
			|||||||
        reversed: Boolean
 | 
					        reversed: Boolean
 | 
				
			||||||
    ): PaginationResult<Value> = count(k).let { count ->
 | 
					    ): PaginationResult<Value> = count(k).let { count ->
 | 
				
			||||||
        val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
 | 
					        val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
 | 
				
			||||||
        helper.readableTransaction {
 | 
					        helper.blockingReadableTransaction {
 | 
				
			||||||
            select(
 | 
					            select(
 | 
				
			||||||
                tableName,
 | 
					                tableName,
 | 
				
			||||||
                selection = "$idColumnName=?",
 | 
					                selection = "$idColumnName=?",
 | 
				
			||||||
@@ -173,7 +171,7 @@ class OneToManyAndroidRepo<Key, Value>(
 | 
				
			|||||||
        reversed: Boolean
 | 
					        reversed: Boolean
 | 
				
			||||||
    ): PaginationResult<Key> = count().let { count ->
 | 
					    ): PaginationResult<Key> = count().let { count ->
 | 
				
			||||||
        val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
 | 
					        val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
 | 
				
			||||||
        helper.readableTransaction {
 | 
					        helper.blockingReadableTransaction {
 | 
				
			||||||
            select(
 | 
					            select(
 | 
				
			||||||
                tableName,
 | 
					                tableName,
 | 
				
			||||||
                limit = resultPagination.limitClause()
 | 
					                limit = resultPagination.limitClause()
 | 
				
			||||||
@@ -198,7 +196,7 @@ class OneToManyAndroidRepo<Key, Value>(
 | 
				
			|||||||
        reversed: Boolean
 | 
					        reversed: Boolean
 | 
				
			||||||
    ): PaginationResult<Key> = count().let { count ->
 | 
					    ): PaginationResult<Key> = count().let { count ->
 | 
				
			||||||
        val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
 | 
					        val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
 | 
				
			||||||
        helper.readableTransaction {
 | 
					        helper.blockingReadableTransaction {
 | 
				
			||||||
            select(
 | 
					            select(
 | 
				
			||||||
                tableName,
 | 
					                tableName,
 | 
				
			||||||
                selection = "$valueColumnName=?",
 | 
					                selection = "$valueColumnName=?",
 | 
				
			||||||
@@ -220,7 +218,7 @@ class OneToManyAndroidRepo<Key, Value>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun remove(toRemove: Map<Key, List<Value>>) {
 | 
					    override suspend fun remove(toRemove: Map<Key, List<Value>>) {
 | 
				
			||||||
        helper.writableTransaction {
 | 
					        helper.blockingWritableTransaction {
 | 
				
			||||||
            toRemove.flatMap { (k, vs) ->
 | 
					            toRemove.flatMap { (k, vs) ->
 | 
				
			||||||
                vs.mapNotNullA { v ->
 | 
					                vs.mapNotNullA { v ->
 | 
				
			||||||
                    if (delete(tableName, "$idColumnName=? AND $valueColumnName=?", arrayOf(k.asId(), v.asValue())) > 0) {
 | 
					                    if (delete(tableName, "$idColumnName=? AND $valueColumnName=?", arrayOf(k.asId(), v.asValue())) > 0) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ String[] includes = [
 | 
				
			|||||||
    ":pagination:ktor:server",
 | 
					    ":pagination:ktor:server",
 | 
				
			||||||
    ":mime_types",
 | 
					    ":mime_types",
 | 
				
			||||||
    ":repos:common",
 | 
					    ":repos:common",
 | 
				
			||||||
 | 
					    ":repos:cache",
 | 
				
			||||||
    ":repos:exposed",
 | 
					    ":repos:exposed",
 | 
				
			||||||
    ":repos:inmemory",
 | 
					    ":repos:inmemory",
 | 
				
			||||||
    ":repos:ktor:client",
 | 
					    ":repos:ktor:client",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user