mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-10-06 15:49:25 +00:00
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
ab7d277167 | |||
8308c1df4d | |||
12c29f5180 | |||
2963098870 | |||
9f56b0a26d | |||
75851312fd | |||
3a3be138a5 | |||
fb7d1f18b0 | |||
d1c6c7696a | |||
5f38d9635d | |||
8185ea87b1 | |||
98bd07d025 | |||
c502c70a21 | |||
d933dc532b | |||
42594f0656 | |||
4b83ca19c3 | |||
bab13f5e83 | |||
14c5f5a26c | |||
b26a4f24d4 | |||
498ec673dc | |||
5c67ab6aec | |||
f78359b5d7 | |||
dbce612cb2 | |||
4322ffdb0a | |||
123b848d74 | |||
b120fbd2b1 | |||
d41c3c2de4 | |||
a3cabd7a9e | |||
3dde486126 | |||
5978122dda | |||
4b4806ce34 |
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 }}
|
35
CHANGELOG.md
35
CHANGELOG.md
@@ -1,5 +1,40 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
* `Repos`
|
||||||
|
* `Exposed`
|
||||||
|
* Fix in `AbstractExposedWriteCRUDRepo`
|
||||||
|
|
||||||
|
## 0.4.26
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Serialization`: `1.0.1` -> `1.1.0`
|
||||||
|
|
||||||
|
## 0.4.25
|
||||||
|
|
||||||
|
* `Matrix`:
|
||||||
|
* Subproject has been created
|
||||||
|
|
||||||
## 0.4.24
|
## 0.4.24
|
||||||
|
|
||||||
* `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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -6,12 +6,12 @@ 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.31
|
||||||
kotlin_coroutines_version=1.4.2
|
kotlin_coroutines_version=1.4.3
|
||||||
kotlin_serialisation_core_version=1.0.1
|
kotlin_serialisation_core_version=1.1.0
|
||||||
kotlin_exposed_version=0.29.1
|
kotlin_exposed_version=0.29.1
|
||||||
|
|
||||||
ktor_version=1.5.1
|
ktor_version=1.5.2
|
||||||
|
|
||||||
klockVersion=2.0.6
|
klockVersion=2.0.6
|
||||||
|
|
||||||
@@ -44,5 +44,5 @@ dokka_version=1.4.20
|
|||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.4.24
|
version=0.4.29
|
||||||
android_code_version=28
|
android_code_version=33
|
||||||
|
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
|
||||||
|
7
matrix/build.gradle
Normal file
7
matrix/build.gradle
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
id "com.android.library"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppProjectWithSerializationPresetPath"
|
@@ -0,0 +1,3 @@
|
|||||||
|
package dev.inmo.micro_utils.matrix
|
||||||
|
|
||||||
|
typealias Matrix<T> = List<Row<T>>
|
@@ -0,0 +1,13 @@
|
|||||||
|
package dev.inmo.micro_utils.matrix
|
||||||
|
|
||||||
|
class MatrixBuilder<T> {
|
||||||
|
private val mutMatrix: MutableList<List<T>> = ArrayList()
|
||||||
|
val matrix: Matrix<T>
|
||||||
|
get() = mutMatrix
|
||||||
|
|
||||||
|
fun row(t: List<T>) = mutMatrix.add(t)
|
||||||
|
operator fun List<T>.unaryPlus() = row(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> MatrixBuilder<T>.row(block: RowBuilder<T>.() -> Unit) = +RowBuilder<T>().also(block).row
|
||||||
|
fun <T> MatrixBuilder<T>.row(vararg elements: T) = +elements.toList()
|
@@ -0,0 +1,17 @@
|
|||||||
|
package dev.inmo.micro_utils.matrix
|
||||||
|
|
||||||
|
fun <T> matrix(block: MatrixBuilder<T>.() -> Unit): Matrix<T> {
|
||||||
|
return MatrixBuilder<T>().also(block).matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> flatMatrix(block: RowBuilder<T>.() -> Unit): Matrix<T> {
|
||||||
|
return MatrixBuilder<T>().apply {
|
||||||
|
row(block)
|
||||||
|
}.matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> flatMatrix(vararg elements: T): Matrix<T> {
|
||||||
|
return MatrixBuilder<T>().apply {
|
||||||
|
row { elements.forEach { +it } }
|
||||||
|
}.matrix
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
package dev.inmo.micro_utils.matrix
|
||||||
|
|
||||||
|
typealias Row<T> = List<T>
|
@@ -0,0 +1,14 @@
|
|||||||
|
package dev.inmo.micro_utils.matrix
|
||||||
|
|
||||||
|
class RowBuilder<T> {
|
||||||
|
private val mutRow: MutableList<T> = ArrayList()
|
||||||
|
val row: Row<T>
|
||||||
|
get() = mutRow
|
||||||
|
|
||||||
|
fun column(t: T) = mutRow.add(t)
|
||||||
|
operator fun T.unaryPlus() = column(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> row(block: RowBuilder<T>.() -> Unit): List<T> = RowBuilder<T>().also(block).row
|
||||||
|
fun <T> RowBuilder<T>.columns(elements: List<T>) = elements.forEach(::column)
|
||||||
|
fun <T> RowBuilder<T>.columns(vararg elements: T) = elements.forEach(::column)
|
@@ -0,0 +1,45 @@
|
|||||||
|
package dev.inmo.micro_utils.matrix
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class SimpleTest {
|
||||||
|
@Test
|
||||||
|
fun simpleTest() {
|
||||||
|
val expected = listOf(
|
||||||
|
listOf(1, 2, 3),
|
||||||
|
listOf(4, 5, 6)
|
||||||
|
)
|
||||||
|
|
||||||
|
val fromMatrixWithVarargs = matrix<Int> {
|
||||||
|
row(1, 2, 3)
|
||||||
|
row(4, 5, 6)
|
||||||
|
}
|
||||||
|
|
||||||
|
val fromMatrixWithColumnsVarargs = matrix<Int> {
|
||||||
|
row {
|
||||||
|
columns(1, 2, 3)
|
||||||
|
}
|
||||||
|
row {
|
||||||
|
columns(4, 5, 6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val fromMatrixWithSimpleAdd = matrix<Int> {
|
||||||
|
row {
|
||||||
|
column(1)
|
||||||
|
column(2)
|
||||||
|
column(3)
|
||||||
|
}
|
||||||
|
row {
|
||||||
|
column(4)
|
||||||
|
column(5)
|
||||||
|
column(6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(expected, fromMatrixWithVarargs)
|
||||||
|
assertEquals(expected, fromMatrixWithColumnsVarargs)
|
||||||
|
assertEquals(expected, fromMatrixWithSimpleAdd)
|
||||||
|
}
|
||||||
|
}
|
1
matrix/src/main/AndroidManifest.xml
Normal file
1
matrix/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.micro_utils.matrix"/>
|
@@ -4,7 +4,9 @@ project.group = "$group"
|
|||||||
apply from: "$publishGradlePath"
|
apply from: "$publishGradlePath"
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvm()
|
jvm {
|
||||||
|
compilations.main.kotlinOptions.useIR = true
|
||||||
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
|
@@ -4,7 +4,9 @@ project.group = "$group"
|
|||||||
apply from: "$publishGradlePath"
|
apply from: "$publishGradlePath"
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvm()
|
jvm {
|
||||||
|
compilations.main.kotlinOptions.useIR = true
|
||||||
|
}
|
||||||
js (BOTH) {
|
js (BOTH) {
|
||||||
browser()
|
browser()
|
||||||
nodejs()
|
nodejs()
|
||||||
|
@@ -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":"","url":"https://git.inmo.dev/InsanusMokrassar/MicroUtils_mirror","vcsUrl":"ssh://git@git.inmo.dev:8322/InsanusMokrassar/MicroUtils_mirror.git","includeGpgSigning":true,"developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}]}}
|
|
@@ -10,13 +10,13 @@ publishing {
|
|||||||
artifact javadocsJar
|
artifact javadocsJar
|
||||||
|
|
||||||
pom {
|
pom {
|
||||||
description = ""
|
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,27 +40,37 @@ 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 {
|
||||||
maven {
|
if ((project.hasProperty('GITHUBPACKAGES_USER') || System.getenv('GITHUBPACKAGES_USER') != null) && (project.hasProperty('GITHUBPACKAGES_PASSWORD') || System.getenv('GITHUBPACKAGES_PASSWORD') != null)) {
|
||||||
name = "bintray"
|
maven {
|
||||||
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")
|
name = "GithubPackages"
|
||||||
credentials {
|
url = uri("https://maven.pkg.github.com/InsanusMokrassar/MicroUtils")
|
||||||
username = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
|
credentials {
|
||||||
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
|
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('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')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signing {
|
signing {
|
||||||
useGpgCmd()
|
useGpgCmd()
|
||||||
publishing.publications.forEach { sign it }
|
sign publishing.publications
|
||||||
}
|
}
|
||||||
|
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/"}]}}
|
@@ -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 {
|
||||||
block(it)
|
safely {
|
||||||
|
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,21 +42,19 @@ 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,
|
idColumnName to ColumnType.Text.NOT_NULLABLE,
|
||||||
idColumnName to ColumnType.Text.NOT_NULLABLE,
|
valueColumnName to ColumnType.Text.NULLABLE
|
||||||
valueColumnName to ColumnType.Text.NULLABLE
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
@@ -60,9 +60,11 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
|
|||||||
}
|
}
|
||||||
}.let {
|
}.let {
|
||||||
if (it > 0) {
|
if (it > 0) {
|
||||||
select {
|
transaction(db = database) {
|
||||||
selectById(this, id)
|
select {
|
||||||
}.limit(1).firstOrNull() ?.asObject
|
selectById(this, id)
|
||||||
|
}.limit(1).firstOrNull() ?.asObject
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ rootProject.name='micro_utils'
|
|||||||
|
|
||||||
String[] includes = [
|
String[] includes = [
|
||||||
":common",
|
":common",
|
||||||
|
":matrix",
|
||||||
":crypto",
|
":crypto",
|
||||||
":selector:common",
|
":selector:common",
|
||||||
":pagination:common",
|
":pagination:common",
|
||||||
|
Reference in New Issue
Block a user