mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-12-26 10:37:14 +00:00
android database improvements
This commit is contained in:
parent
5f38d9635d
commit
d1c6c7696a
@ -4,6 +4,11 @@
|
||||
|
||||
* `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
|
||||
|
||||
## 0.4.28
|
||||
|
||||
|
@ -32,7 +32,9 @@ private object ContextsPool {
|
||||
|
||||
suspend fun <T> use(block: suspend (CoroutineContext) -> T): T = acquireContext().let {
|
||||
try {
|
||||
block(it)
|
||||
safely {
|
||||
block(it)
|
||||
}
|
||||
} finally {
|
||||
freeContext(it)
|
||||
}
|
||||
@ -48,11 +50,12 @@ class TransactionContext(
|
||||
}
|
||||
|
||||
suspend fun <T> SQLiteDatabase.transaction(block: suspend SQLiteDatabase.() -> T): T {
|
||||
return coroutineContext[TransactionContext] ?.let {
|
||||
withContext(it.databaseContext) {
|
||||
coroutineContext[TransactionContext] ?.let {
|
||||
return withContext(it.databaseContext) {
|
||||
block()
|
||||
}
|
||||
} ?: ContextsPool.use { context ->
|
||||
}
|
||||
return ContextsPool.use { context ->
|
||||
withContext(TransactionContext(context) + context) {
|
||||
beginTransaction()
|
||||
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 {
|
||||
inTransaction() -> block()
|
||||
else -> {
|
||||
beginTransaction()
|
||||
try {
|
||||
block().also {
|
||||
setTransactionSuccessful()
|
||||
}
|
||||
block().also { setTransactionSuccessful() }
|
||||
} finally {
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
return writableDatabase.transaction(block)
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ abstract class AbstractAndroidCRUDRepo<ObjectType, IdType>(
|
||||
it.count
|
||||
}.toLong()
|
||||
|
||||
override suspend fun contains(id: IdType): Boolean = helper.readableTransaction {
|
||||
override suspend fun contains(id: IdType): Boolean = helper.blockingReadableTransaction {
|
||||
select(
|
||||
tableName,
|
||||
null,
|
||||
|
@ -19,9 +19,10 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
|
||||
protected abstract suspend fun InputValueType.asContentValues(id: IdType? = null): ContentValues
|
||||
|
||||
override suspend fun create(values: List<InputValueType>): List<ObjectType> {
|
||||
val indexes = helper.writableTransaction {
|
||||
values.map {
|
||||
insert(tableName, null, it.asContentValues())
|
||||
val valuesContentValues = values.map { it.asContentValues() }
|
||||
val indexes = helper.blockingWritableTransaction {
|
||||
valuesContentValues.map {
|
||||
insert(tableName, null, it)
|
||||
}
|
||||
}
|
||||
return helper.readableTransaction {
|
||||
@ -47,7 +48,7 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
|
||||
|
||||
override suspend fun deleteById(ids: List<IdType>) {
|
||||
val deleted = mutableListOf<IdType>()
|
||||
helper.writableTransaction {
|
||||
helper.blockingWritableTransaction {
|
||||
ids.forEach { id ->
|
||||
delete(tableName, "$idColumnName=?", arrayOf(id.asId)).also {
|
||||
if (it > 0) {
|
||||
@ -64,7 +65,7 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
|
||||
override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
|
||||
val asContentValues = value.asContentValues(id)
|
||||
if (asContentValues.keySet().isNotEmpty()) {
|
||||
helper.writableTransaction {
|
||||
helper.blockingWritableTransaction {
|
||||
update(
|
||||
tableName,
|
||||
asContentValues,
|
||||
@ -79,11 +80,12 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
|
||||
}
|
||||
|
||||
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> {
|
||||
val contentValues = values.map { (id, value) -> id to value.asContentValues(id) }
|
||||
helper.writableTransaction {
|
||||
values.forEach { (id, value) ->
|
||||
contentValues.forEach { (id, contentValues) ->
|
||||
update(
|
||||
tableName,
|
||||
value.asContentValues(id),
|
||||
contentValues,
|
||||
"$idColumnName=?",
|
||||
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)
|
||||
|
||||
init {
|
||||
runBlocking(DatabaseCoroutineContext) {
|
||||
helper.writableTransaction {
|
||||
createTable(
|
||||
tableName,
|
||||
internalId to internalIdType,
|
||||
idColumnName to ColumnType.Text.NOT_NULLABLE,
|
||||
valueColumnName to ColumnType.Text.NULLABLE
|
||||
)
|
||||
}
|
||||
helper.blockingWritableTransaction {
|
||||
createTable(
|
||||
tableName,
|
||||
internalId to internalIdType,
|
||||
idColumnName to ColumnType.Text.NOT_NULLABLE,
|
||||
valueColumnName to ColumnType.Text.NULLABLE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun add(toAdd: Map<Key, List<Value>>) {
|
||||
val added = mutableListOf<Pair<Key, Value>>()
|
||||
helper.writableTransaction {
|
||||
helper.blockingWritableTransaction {
|
||||
toAdd.forEach { (k, values) ->
|
||||
values.forEach { v ->
|
||||
insert(
|
||||
@ -78,7 +76,7 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
}
|
||||
|
||||
override suspend fun clear(k: Key) {
|
||||
helper.writableTransaction {
|
||||
helper.blockingWritableTransaction {
|
||||
delete(tableName, "$idColumnName=?", arrayOf(k.asId()))
|
||||
}.also {
|
||||
if (it > 0) {
|
||||
@ -88,7 +86,7 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
}
|
||||
|
||||
override suspend fun set(toSet: Map<Key, List<Value>>) {
|
||||
val (clearedKeys, inserted) = helper.writableTransaction {
|
||||
val (clearedKeys, inserted) = helper.blockingWritableTransaction {
|
||||
toSet.mapNotNull { (k, _) ->
|
||||
if (delete(tableName, "$idColumnName=?", arrayOf(k.asId())) > 0) {
|
||||
k
|
||||
@ -110,13 +108,13 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
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 {
|
||||
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(
|
||||
tableName,
|
||||
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(
|
||||
tableName
|
||||
).use {
|
||||
@ -135,7 +133,7 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
}
|
||||
}.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 {
|
||||
it.count
|
||||
}
|
||||
@ -147,7 +145,7 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
reversed: Boolean
|
||||
): PaginationResult<Value> = count(k).let { count ->
|
||||
val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
|
||||
helper.readableTransaction {
|
||||
helper.blockingReadableTransaction {
|
||||
select(
|
||||
tableName,
|
||||
selection = "$idColumnName=?",
|
||||
@ -173,7 +171,7 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
reversed: Boolean
|
||||
): PaginationResult<Key> = count().let { count ->
|
||||
val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
|
||||
helper.readableTransaction {
|
||||
helper.blockingReadableTransaction {
|
||||
select(
|
||||
tableName,
|
||||
limit = resultPagination.limitClause()
|
||||
@ -198,7 +196,7 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
reversed: Boolean
|
||||
): PaginationResult<Key> = count().let { count ->
|
||||
val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
|
||||
helper.readableTransaction {
|
||||
helper.blockingReadableTransaction {
|
||||
select(
|
||||
tableName,
|
||||
selection = "$valueColumnName=?",
|
||||
@ -220,7 +218,7 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
}
|
||||
|
||||
override suspend fun remove(toRemove: Map<Key, List<Value>>) {
|
||||
helper.writableTransaction {
|
||||
helper.blockingWritableTransaction {
|
||||
toRemove.flatMap { (k, vs) ->
|
||||
vs.mapNotNullA { v ->
|
||||
if (delete(tableName, "$idColumnName=? AND $valueColumnName=?", arrayOf(k.asId(), v.asValue())) > 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user