From 30d1453a12c53df0b8750c80c3981bd15052a20c Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 22 Nov 2020 17:49:39 +0600 Subject: [PATCH 1/8] start 0.4.4 --- CHANGELOG.md | 2 ++ gradle.properties | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1d7de03327..1f9ba5e143e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +## 0.4.4 + ## 0.4.3 * `Versions`: diff --git a/gradle.properties b/gradle.properties index 334d0f94298..e3b715031b7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -41,5 +41,5 @@ dokka_version=1.4.0 # Project data group=dev.inmo -version=0.4.3 -android_code_version=7 +version=0.4.4 +android_code_version=8 From c40f0fdcb9a0c8cdcb42b49b2572900c82e8c843 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 22 Nov 2020 19:07:37 +0600 Subject: [PATCH 2/8] VersionsRepo --- CHANGELOG.md | 7 +++ .../KeyValueBasedVersionsRepoProxy.kt | 13 ++++ .../repos/versions/StandardVersionsRepo.kt | 36 +++++++++++ .../repos/versions/VersionsRepo.kt | 31 +++++++++ .../micro_utils/repos/StandardSQLHelper.kt | 4 ++ .../AndroidSQLStandardVersionsRepoProxy.kt | 63 +++++++++++++++++++ ...redPreferencesStandardVersionsRepoProxy.kt | 49 +++++++++++++++ .../ExposedStandardVersionsRepoProxy.kt | 48 ++++++++++++++ 8 files changed, 251 insertions(+) create mode 100644 repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/KeyValueBasedVersionsRepoProxy.kt create mode 100644 repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/StandardVersionsRepo.kt create mode 100644 repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/VersionsRepo.kt create mode 100644 repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt create mode 100644 repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSharedPreferencesStandardVersionsRepoProxy.kt create mode 100644 repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/versions/ExposedStandardVersionsRepoProxy.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f9ba5e143e..cb9967a2b08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## 0.4.4 +* `Repos`: + * Add interface `VersionsRepo` + * Add default realization of `VersionsRepo` named `StandardVersionsRepo` which use `StandardVersionsRepoProxy` + to get access to some end-store + * Add default realization of `StandardVersionsRepoProxy` based on `KeyValue` repos + * Add realizations of `StandardVersionsRepoProxy` for exposed and android (`SQL` and `SharedPreferences`) + ## 0.4.3 * `Versions`: diff --git a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/KeyValueBasedVersionsRepoProxy.kt b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/KeyValueBasedVersionsRepoProxy.kt new file mode 100644 index 00000000000..5d7e3435670 --- /dev/null +++ b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/KeyValueBasedVersionsRepoProxy.kt @@ -0,0 +1,13 @@ +package dev.inmo.micro_utils.repos.versions + +import dev.inmo.micro_utils.repos.StandardKeyValueRepo +import dev.inmo.micro_utils.repos.set + +class KeyValueBasedVersionsRepoProxy( + private val keyValueStore: StandardKeyValueRepo, + override val database: T +) : StandardVersionsRepoProxy { + override suspend fun getTableVersion(tableName: String): Int? = keyValueStore.get(tableName) + + override suspend fun updateTableVersion(tableName: String, version: Int) { keyValueStore.set(tableName, version) } +} diff --git a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/StandardVersionsRepo.kt b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/StandardVersionsRepo.kt new file mode 100644 index 00000000000..b02432c2759 --- /dev/null +++ b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/StandardVersionsRepo.kt @@ -0,0 +1,36 @@ +package dev.inmo.micro_utils.repos.versions + +import dev.inmo.micro_utils.repos.Repo + +interface StandardVersionsRepoProxy : Repo { + val database: T + + suspend fun getTableVersion(tableName: String): Int? + suspend fun updateTableVersion(tableName: String, version: Int) +} + +class StandardVersionsRepo( + private val proxy: StandardVersionsRepoProxy +) : VersionsRepo { + override suspend fun setTableVersion( + tableName: String, + version: Int, + onCreate: suspend T.() -> Unit, + onUpdate: suspend T.(from: Int, to: Int) -> Unit + ) { + var savedVersion = proxy.getTableVersion(tableName) + if (savedVersion == null) { + proxy.database.onCreate() + proxy.updateTableVersion(tableName, version) + } else { + while (savedVersion != null && savedVersion < version) { + val newVersion = savedVersion + 1 + + proxy.database.onUpdate(savedVersion, newVersion) + + proxy.updateTableVersion(tableName, newVersion) + savedVersion = newVersion + } + } + } +} \ No newline at end of file diff --git a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/VersionsRepo.kt b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/VersionsRepo.kt new file mode 100644 index 00000000000..e026f425924 --- /dev/null +++ b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/VersionsRepo.kt @@ -0,0 +1,31 @@ +package dev.inmo.micro_utils.repos.versions + +import dev.inmo.micro_utils.repos.Repo + +/** + * This interface has been created due to requirement to work with different versions of databases and make some + * migrations between versions + * + * @param T It is a type of database, which will be used by this repo to retrieve current table version and update it + */ +interface VersionsRepo : Repo { + /** + * By default, instance of this interface will check that version of table with name [tableName] is less than + * [version] or is absent + * + * * In case if [tableName] didn't found, will be called [onCreate] and version of table will be set up to [version] + * * In case if [tableName] have version less than parameter [version], it will increase version one-by-one + * until database version will be equal to [version] + * + * @param version Current version of table + * @param onCreate This callback will be called in case when table have no information about table + * @param onUpdate This callback will be called after **iterative** changing of version. It is expected that parameter + * "to" will always be greater than "from" + */ + suspend fun setTableVersion( + tableName: String, + version: Int, + onCreate: suspend T.() -> Unit, + onUpdate: suspend T.(from: Int, to: Int) -> Unit + ) +} diff --git a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/StandardSQLHelper.kt b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/StandardSQLHelper.kt index 8de4676138a..16cd3d02d58 100644 --- a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/StandardSQLHelper.kt +++ b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/StandardSQLHelper.kt @@ -5,6 +5,7 @@ import android.database.DatabaseErrorHandler import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper import dev.inmo.micro_utils.coroutines.safely +import dev.inmo.micro_utils.repos.versions.* import kotlin.coroutines.Continuation import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -36,6 +37,9 @@ class StandardSQLHelper( override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {} } + val versionsRepo: VersionsRepo by lazy { + StandardVersionsRepo(AndroidSQLStandardVersionsRepoProxy(sqlOpenHelper)) + } suspend fun writableTransaction(block: suspend SQLiteDatabase.() -> T): T = sqlOpenHelper.writableTransaction(block) diff --git a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt new file mode 100644 index 00000000000..a0f71c3f993 --- /dev/null +++ b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt @@ -0,0 +1,63 @@ +package dev.inmo.micro_utils.repos.versions + +import android.database.sqlite.SQLiteOpenHelper +import androidx.core.content.contentValuesOf +import dev.inmo.micro_utils.repos.* +import kotlinx.coroutines.runBlocking + +/** + * Will create [VersionsRepo] based on [SQLiteOpenHelper] with table inside of [database] + */ +@Suppress("NOTHING_TO_INLINE") +inline fun versionsRepo(database: SQLiteOpenHelper): VersionsRepo = StandardVersionsRepo( + AndroidSQLStandardVersionsRepoProxy(database) +) + +class AndroidSQLStandardVersionsRepoProxy( + override val database: SQLiteOpenHelper +) : StandardVersionsRepoProxy { + private val tableName: String = "AndroidSQLStandardVersionsRepo" + private val tableNameColumnName = "tableName" + private val tableVersionColumnName = "version" + + init { + runBlocking(DatabaseCoroutineContext) { + database.writableTransaction { + createTable( + tableName, + tableNameColumnName to ColumnType.Text.NOT_NULLABLE, + tableVersionColumnName to ColumnType.Numeric.INTEGER() + ) + } + } + } + + override suspend fun getTableVersion(tableName: String): Int? = database.writableTransaction { + select( + tableName, + selection = "$tableNameColumnName=?", + selectionArgs = arrayOf(tableName), + limit = limitClause(1) + ).use { + if (it.moveToFirst()) { + it.getInt(tableVersionColumnName) + } else { + null + } + } + } + + override suspend fun updateTableVersion(tableName: String, version: Int) { + database.writableTransaction { + val updated = update( + tableName, + contentValuesOf(tableVersionColumnName to version), + "$tableNameColumnName=?", + arrayOf(version.toString()) + ) > 0 + if (!updated) { + insert(tableName, null, contentValuesOf(tableNameColumnName to tableName, tableVersionColumnName to version)) + } + } + } +} diff --git a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSharedPreferencesStandardVersionsRepoProxy.kt b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSharedPreferencesStandardVersionsRepoProxy.kt new file mode 100644 index 00000000000..1e9f1e1c1a4 --- /dev/null +++ b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSharedPreferencesStandardVersionsRepoProxy.kt @@ -0,0 +1,49 @@ +@file:Suppress("NOTHING_TO_INLINE") + +package dev.inmo.micro_utils.repos.versions + +import android.content.Context +import android.database.sqlite.SQLiteOpenHelper +import androidx.core.content.contentValuesOf +import dev.inmo.micro_utils.repos.* +import dev.inmo.micro_utils.repos.keyvalue.keyValueStore +import kotlinx.coroutines.runBlocking + +/** + * Will create [VersionsRepo] based on [T], but versions will be stored in [StandardKeyValueRepo] + * + * @receiver Will be used to create [KeyValueBasedVersionsRepoProxy] via [keyValueStore] and pass it to [StandardVersionsRepo] + * + * @see [KeyValueBasedVersionsRepoProxy] + * @see [keyValueStore] + */ +inline fun Context.versionsKeyValueRepo( + database: T +): VersionsRepo = StandardVersionsRepo( + KeyValueBasedVersionsRepoProxy( + keyValueStore("SPVersionsRepo"), + database + ) +) +/** + * Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [StandardKeyValueRepo] + * + * @receiver Will be used to create [StandardKeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo] + * + * @see [keyValueStore] + */ +inline fun Context.versionsKeyValueRepoForSQL( + database: SQLiteOpenHelper +) = versionsKeyValueRepo(database) + +/** + * Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [StandardKeyValueRepo] + * + * @param context Will be used to create [StandardKeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo] + * + * @see [keyValueStore] + */ +inline fun versionsRepo( + context: Context, + database: SQLiteOpenHelper +) = context.versionsKeyValueRepoForSQL(database) diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/versions/ExposedStandardVersionsRepoProxy.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/versions/ExposedStandardVersionsRepoProxy.kt new file mode 100644 index 00000000000..a561949537e --- /dev/null +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/versions/ExposedStandardVersionsRepoProxy.kt @@ -0,0 +1,48 @@ +package dev.inmo.micro_utils.repos.exposed.versions + +import dev.inmo.micro_utils.repos.exposed.ExposedRepo +import dev.inmo.micro_utils.repos.exposed.initTable +import dev.inmo.micro_utils.repos.versions.* +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction + +/** + * Use this method to create [StandardVersionsRepo] based on [Database] with [ExposedStandardVersionsRepoProxy] as + * [StandardVersionsRepoProxy] + */ +@Suppress("NOTHING_TO_INLINE") +inline fun versionsRepo(database: Database): VersionsRepo = StandardVersionsRepo( + ExposedStandardVersionsRepoProxy(database) +) + +class ExposedStandardVersionsRepoProxy( + override val database: Database +) : StandardVersionsRepoProxy, Table("ExposedVersionsProxy"), ExposedRepo { + private val tableNameColumn = text("tableName") + private val tableVersionColumn = integer("tableName") + + init { + initTable() + } + + override suspend fun getTableVersion(tableName: String): Int? = transaction(database) { + select { tableNameColumn.eq(tableName) }.limit(1).firstOrNull() ?.getOrNull(tableVersionColumn) + } + + override suspend fun updateTableVersion(tableName: String, version: Int) { + transaction(database) { + val updated = update( + { tableNameColumn.eq(tableName) } + ) { + it[tableVersionColumn] = version + } > 0 + if (!updated) { + insert { + it[tableNameColumn] = tableName + it[tableVersionColumn] = version + } + } + } + } + +} From 8bee29f6834ca69e86655eec4351adff2588681f Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 22 Nov 2020 19:12:10 +0600 Subject: [PATCH 3/8] update version of klock and remove gradle bintray plugin --- CHANGELOG.md | 2 ++ build.gradle | 3 +-- gradle.properties | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb9967a2b08..3d112549136 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## 0.4.4 +* `Versions`: + * `Klock`: `1.12.1` -> `2.0.0` * `Repos`: * Add interface `VersionsRepo` * Add default realization of `VersionsRepo` named `StandardVersionsRepo` which use `StandardVersionsRepoProxy` diff --git a/build.gradle b/build.gradle index c6d3e1911c6..07759c6e7bf 100644 --- a/build.gradle +++ b/build.gradle @@ -8,10 +8,9 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.0.0' + classpath 'com.android.tools.build:gradle:4.0.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" - classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version" classpath "com.getkeepsafe.dexcount:dexcount-gradle-plugin:$dexcount_version" classpath "com.github.breadmoirai:github-release:$github_release_plugin_version" classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" diff --git a/gradle.properties b/gradle.properties index e3b715031b7..0e57629edc6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,9 +14,8 @@ kotlin_exposed_version=0.28.1 ktor_version=1.4.2 -klockVersion=1.12.1 +klockVersion=2.0.0 -gradle_bintray_plugin_version=1.8.5 github_release_plugin_version=2.2.12 uuidVersion=0.2.2 From 6bbe3a271f9c880dd097a5d01ace27511984f526 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 22 Nov 2020 19:27:53 +0600 Subject: [PATCH 4/8] update defaults in VersionsRepo --- .../dev/inmo/micro_utils/repos/versions/VersionsRepo.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/VersionsRepo.kt b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/VersionsRepo.kt index e026f425924..ee7cbab700f 100644 --- a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/VersionsRepo.kt +++ b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/versions/VersionsRepo.kt @@ -25,7 +25,7 @@ interface VersionsRepo : Repo { suspend fun setTableVersion( tableName: String, version: Int, - onCreate: suspend T.() -> Unit, - onUpdate: suspend T.(from: Int, to: Int) -> Unit + onCreate: suspend T.() -> Unit = {}, + onUpdate: suspend T.(from: Int, to: Int) -> Unit = { _, _ ->} ) } From 3de5558ed47278d7c04901022500b0fe883abb46 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 22 Nov 2020 21:51:33 +0600 Subject: [PATCH 5/8] new mechanism of transactions --- CHANGELOG.md | 2 ++ .../micro_utils/repos/DatabaseTransactions.kt | 19 +++++++++++++------ .../AndroidSQLStandardVersionsRepoProxy.kt | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d112549136..49acddbaef2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ to get access to some end-store * Add default realization of `StandardVersionsRepoProxy` based on `KeyValue` repos * Add realizations of `StandardVersionsRepoProxy` for exposed and android (`SQL` and `SharedPreferences`) + * `Commons`: + * In Android ## 0.4.3 diff --git a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt index 1ac58f237a5..bef95829df5 100644 --- a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt +++ b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt @@ -2,15 +2,22 @@ package dev.inmo.micro_utils.repos import android.database.sqlite.SQLiteDatabase import dev.inmo.micro_utils.coroutines.safely +import kotlinx.coroutines.newSingleThreadContext import kotlinx.coroutines.withContext +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.coroutineContext + +object InTransaction: CoroutineContext.Element, CoroutineContext.Key { + override val key: CoroutineContext.Key = InTransaction +} suspend fun SQLiteDatabase.transaction(block: suspend SQLiteDatabase.() -> T): T { - return withContext(DatabaseCoroutineContext) { - when { - inTransaction() -> { - block() - } - else -> { + return when { + coroutineContext[InTransaction] == InTransaction -> { + block() + } + else -> { + withContext(InTransaction) { beginTransaction() safely( { diff --git a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt index a0f71c3f993..81d31449a9b 100644 --- a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt +++ b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt @@ -26,7 +26,7 @@ class AndroidSQLStandardVersionsRepoProxy( createTable( tableName, tableNameColumnName to ColumnType.Text.NOT_NULLABLE, - tableVersionColumnName to ColumnType.Numeric.INTEGER() + tableVersionColumnName to ColumnType.Numeric.INTEGER() ) } } From 615f7f99c3796c2f0ea92ac9c3ee1a8f665f297c Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 22 Nov 2020 22:00:50 +0600 Subject: [PATCH 6/8] one more time update mechanism of sql transactions in android --- .../micro_utils/repos/DatabaseTransactions.kt | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt index bef95829df5..2f2c5e21f1e 100644 --- a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt +++ b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt @@ -2,33 +2,36 @@ package dev.inmo.micro_utils.repos import android.database.sqlite.SQLiteDatabase import dev.inmo.micro_utils.coroutines.safely -import kotlinx.coroutines.newSingleThreadContext -import kotlinx.coroutines.withContext +import kotlinx.coroutines.* +import java.util.concurrent.Executors import kotlin.coroutines.CoroutineContext import kotlin.coroutines.coroutineContext -object InTransaction: CoroutineContext.Element, CoroutineContext.Key { - override val key: CoroutineContext.Key = InTransaction +class TransactionContext( + val databaseContext: CoroutineContext +): CoroutineContext.Element { + override val key: CoroutineContext.Key = TransactionContext + + companion object : CoroutineContext.Key } suspend fun SQLiteDatabase.transaction(block: suspend SQLiteDatabase.() -> T): T { - return when { - coroutineContext[InTransaction] == InTransaction -> { + return coroutineContext[TransactionContext] ?.let { + withContext(it.databaseContext) { block() } - else -> { - withContext(InTransaction) { - beginTransaction() - safely( - { - endTransaction() - throw it - } - ) { - block().also { - setTransactionSuccessful() - endTransaction() - } + } ?: Executors.newSingleThreadExecutor().asCoroutineDispatcher().let { context -> + withContext(TransactionContext(context) + context) { + beginTransaction() + safely( + { + endTransaction() + throw it + } + ) { + block().also { + setTransactionSuccessful() + endTransaction() } } } From 07a65e0bb5b4efcb838ad82888864d8a61850a67 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 22 Nov 2020 23:19:16 +0600 Subject: [PATCH 7/8] fixes --- .../repos/DatabaseCoroutineContext.kt | 4 +-- .../micro_utils/repos/DatabaseTransactions.kt | 34 ++++++++++++++++++- .../AndroidSQLStandardVersionsRepoProxy.kt | 10 +++--- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseCoroutineContext.kt b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseCoroutineContext.kt index 8a2932eb0fe..b99835e5972 100644 --- a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseCoroutineContext.kt +++ b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseCoroutineContext.kt @@ -1,6 +1,6 @@ package dev.inmo.micro_utils.repos -import kotlinx.coroutines.newSingleThreadContext +import kotlinx.coroutines.Dispatchers import kotlin.coroutines.CoroutineContext -val DatabaseCoroutineContext: CoroutineContext = newSingleThreadContext("db-context") +val DatabaseCoroutineContext: CoroutineContext = Dispatchers.IO diff --git a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt index 2f2c5e21f1e..6d7821d20ca 100644 --- a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt +++ b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/DatabaseTransactions.kt @@ -3,10 +3,42 @@ package dev.inmo.micro_utils.repos import android.database.sqlite.SQLiteDatabase import dev.inmo.micro_utils.coroutines.safely import kotlinx.coroutines.* +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import java.util.concurrent.Executors import kotlin.coroutines.CoroutineContext import kotlin.coroutines.coroutineContext +private object ContextsPool { + private val contexts = mutableListOf() + private val mutex = Mutex(locked = false) + private val freeContexts = mutableListOf() + + suspend fun acquireContext(): CoroutineContext { + return mutex.withLock { + freeContexts.removeFirstOrNull() ?: Executors.newSingleThreadExecutor().asCoroutineDispatcher().also { + contexts.add(it) + } + } + } + + suspend fun freeContext(context: CoroutineContext) { + return mutex.withLock { + if (context in contexts && context !in freeContexts) { + freeContexts.add(context) + } + } + } + + suspend fun use(block: suspend (CoroutineContext) -> T): T = acquireContext().let { + try { + block(it) + } finally { + freeContext(it) + } + } +} + class TransactionContext( val databaseContext: CoroutineContext ): CoroutineContext.Element { @@ -20,7 +52,7 @@ suspend fun SQLiteDatabase.transaction(block: suspend SQLiteDatabase.() -> T withContext(it.databaseContext) { block() } - } ?: Executors.newSingleThreadExecutor().asCoroutineDispatcher().let { context -> + } ?: ContextsPool.use { context -> withContext(TransactionContext(context) + context) { beginTransaction() safely( diff --git a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt index 81d31449a9b..d52d9e9ddad 100644 --- a/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt +++ b/repos/common/src/main/kotlin/dev/inmo/micro_utils/repos/versions/AndroidSQLStandardVersionsRepoProxy.kt @@ -32,11 +32,11 @@ class AndroidSQLStandardVersionsRepoProxy( } } - override suspend fun getTableVersion(tableName: String): Int? = database.writableTransaction { + override suspend fun getTableVersion(table: String): Int? = database.writableTransaction { select( tableName, selection = "$tableNameColumnName=?", - selectionArgs = arrayOf(tableName), + selectionArgs = arrayOf(table), limit = limitClause(1) ).use { if (it.moveToFirst()) { @@ -47,16 +47,16 @@ class AndroidSQLStandardVersionsRepoProxy( } } - override suspend fun updateTableVersion(tableName: String, version: Int) { + override suspend fun updateTableVersion(table: String, version: Int) { database.writableTransaction { val updated = update( tableName, contentValuesOf(tableVersionColumnName to version), "$tableNameColumnName=?", - arrayOf(version.toString()) + arrayOf(table) ) > 0 if (!updated) { - insert(tableName, null, contentValuesOf(tableNameColumnName to tableName, tableVersionColumnName to version)) + insert(tableName, null, contentValuesOf(tableNameColumnName to table, tableVersionColumnName to version)) } } } From 1a41f37a9d2a7e76a8b879dfad93f085982f114e Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 22 Nov 2020 23:42:01 +0600 Subject: [PATCH 8/8] update changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49acddbaef2..b19566594cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,8 @@ * Add default realization of `StandardVersionsRepoProxy` based on `KeyValue` repos * Add realizations of `StandardVersionsRepoProxy` for exposed and android (`SQL` and `SharedPreferences`) * `Commons`: - * In Android + * In Android fully reworked transactions functions + * Now `DatabaseCoroutineContext` is a shortcut for `Dispatchers.IO` ## 0.4.3 @@ -257,4 +258,4 @@ All deprecations has been removed ## 0.1.0 -Inited :) \ No newline at end of file +Inited :)