MicroUtils/repos/common/src/androidMain/kotlin/dev/inmo/micro_utils/repos/crud/AbstractMutableAndroidCRUDR...

108 lines
3.9 KiB
Kotlin

package dev.inmo.micro_utils.repos.crud
import android.content.ContentValues
import dev.inmo.micro_utils.common.mapNotNullA
import dev.inmo.micro_utils.repos.*
import kotlinx.coroutines.flow.*
abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType>(
helper: StandardSQLHelper,
replyInFlows: Int = 0,
extraBufferCapacityInFlows: Int = 64
) : WriteCRUDRepo<ObjectType, IdType, InputValueType>,
AbstractAndroidCRUDRepo<ObjectType, IdType>(helper),
CRUDRepo<ObjectType, IdType, InputValueType> {
protected val newObjectsChannel = MutableSharedFlow<ObjectType>(replyInFlows, extraBufferCapacityInFlows)
protected val updateObjectsChannel = MutableSharedFlow<ObjectType>(replyInFlows, extraBufferCapacityInFlows)
protected val deleteObjectsIdsChannel = MutableSharedFlow<IdType>(replyInFlows, extraBufferCapacityInFlows)
override val newObjectsFlow: Flow<ObjectType> = newObjectsChannel.asSharedFlow()
override val updatedObjectsFlow: Flow<ObjectType> = updateObjectsChannel.asSharedFlow()
override val deletedObjectsIdsFlow: Flow<IdType> = deleteObjectsIdsChannel.asSharedFlow()
protected abstract suspend fun InputValueType.asContentValues(id: IdType? = null): ContentValues
override suspend fun create(values: List<InputValueType>): List<ObjectType> {
val valuesContentValues = values.map { it.asContentValues() }
val indexes = helper.blockingWritableTransaction {
valuesContentValues.map {
insert(tableName, null, it)
}
}
return helper.readableTransaction {
indexes.mapNotNullA { i ->
select(
tableName,
selection = "$internalId=?",
selectionArgs = arrayOf(i.toString())
).use { c ->
if (c.moveToFirst()) {
c.toObject()
} else {
null
}
}
}
}.also {
it.forEach {
newObjectsChannel.emit(it)
}
}
}
override suspend fun deleteById(ids: List<IdType>) {
val deleted = mutableListOf<IdType>()
helper.blockingWritableTransaction {
for (id in ids) {
delete(tableName, "$idColumnName=?", arrayOf(id.asId)).also {
if (it > 0) {
deleted.add(id)
}
}
}
}
for (deletedItem in deleted) {
deleteObjectsIdsChannel.emit(deletedItem)
}
}
override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
val asContentValues = value.asContentValues(id)
if (asContentValues.keySet().isNotEmpty()) {
helper.blockingWritableTransaction {
update(
tableName,
asContentValues,
"$idColumnName=?",
arrayOf(id.asId)
)
}
}
return getById(id) ?.also {
updateObjectsChannel.emit(it)
}
}
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> {
val contentValues = values.map { (id, value) -> id to value.asContentValues(id) }
helper.writableTransaction {
contentValues.forEach { (id, contentValues) ->
update(
tableName,
contentValues,
"$idColumnName=?",
arrayOf(id.asId)
)
}
}
return values.mapNotNullA {
getById(it.first)
}.also {
it.forEach {
updateObjectsChannel.emit(it)
}
}
}
override suspend fun count(): Long = helper.blockingReadableTransaction { select(tableName).use { it.count.toLong() } }
}