From 193d22ff20ab25243504439287ab7954cb00b21d Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 22 Aug 2022 00:02:34 +0600 Subject: [PATCH 1/5] start 0.12.3 --- CHANGELOG.md | 2 ++ gradle.properties | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00805ce107c..801f8f0164e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +## 0.12.3 + ## 0.12.2 * `Versions`: diff --git a/gradle.properties b/gradle.properties index c95fc99251b..7b47e67542c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,5 +14,5 @@ crypto_js_version=4.1.1 # Project data group=dev.inmo -version=0.12.2 -android_code_version=141 +version=0.12.3 +android_code_version=142 From 7c5fc9bf7caaf265abc3ebad573a0ca4330b02ea Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 22 Aug 2022 01:11:09 +0600 Subject: [PATCH 2/5] selectPaginated and abstract exposed keyvalue(s) repos --- CHANGELOG.md | 5 ++ .../exposed/AbstractExposedWriteCRUDRepo.kt | 1 - .../repos/exposed/CommonExposedRepo.kt | 9 +++ .../repos/exposed/ExposedCRUDRepo.kt | 5 +- .../keyvalue/AbstractExposedKeyValueRepo.kt | 72 ++++++++++++++++++ .../AbstractExposedReadKeyValueRepo.kt | 60 +++++++++++++++ .../keyvalue/ExposedReadKeyValueRepo.kt | 2 + .../onetomany/AbstractExposedKeyValueRepo.kt | 69 +++++++++++++++++ .../AbstractExposedReadKeyValueRepo.kt | 74 +++++++++++++++++++ .../repos/exposed/utils/PaginatedSelect.kt | 21 ++++++ 10 files changed, 313 insertions(+), 5 deletions(-) create mode 100644 repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt create mode 100644 repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/AbstractExposedKeyValueRepo.kt create mode 100644 repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/AbstractExposedReadKeyValueRepo.kt create mode 100644 repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedKeyValueRepo.kt create mode 100644 repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedReadKeyValueRepo.kt create mode 100644 repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/utils/PaginatedSelect.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 801f8f0164e..ccb6108563b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## 0.12.3 +* `Repos`: + * `Exposed`: + * Add abstract exposed variants of `KeyValue` and `KeyValues` repos + * Add new extension `Query#selectPaginated` + ## 0.12.2 * `Versions`: diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt index 5b6588880b7..6bb44a53052 100644 --- a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt @@ -26,7 +26,6 @@ abstract class AbstractExposedWriteCRUDRepo( override val deletedObjectsIdsFlow: Flow = _deletedObjectsIdsFlow.asSharedFlow() protected abstract fun InsertStatement.asObject(value: InputValueType): ObjectType - abstract val selectByIds: SqlExpressionBuilder.(List) -> Op protected abstract fun insert(value: InputValueType, it: InsertStatement) protected abstract fun update(id: IdType, value: InputValueType, it: UpdateStatement) diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt new file mode 100644 index 00000000000..f30da0c9eda --- /dev/null +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt @@ -0,0 +1,9 @@ +package dev.inmo.micro_utils.repos.exposed + +import org.jetbrains.exposed.sql.* + +interface CommonExposedRepo : ExposedRepo { + val ResultRow.asObject: ObjectType + val selectById: SqlExpressionBuilder.(IdType) -> Op + val selectByIds: SqlExpressionBuilder.(List) -> Op +} diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/ExposedCRUDRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/ExposedCRUDRepo.kt index a7505f5e727..258e62b7950 100644 --- a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/ExposedCRUDRepo.kt +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/ExposedCRUDRepo.kt @@ -2,7 +2,4 @@ package dev.inmo.micro_utils.repos.exposed import org.jetbrains.exposed.sql.* -interface ExposedCRUDRepo : ExposedRepo { - val ResultRow.asObject: ObjectType - val selectById: SqlExpressionBuilder.(IdType) -> Op -} +interface ExposedCRUDRepo : CommonExposedRepo diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/AbstractExposedKeyValueRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/AbstractExposedKeyValueRepo.kt new file mode 100644 index 00000000000..528c669ec8b --- /dev/null +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/AbstractExposedKeyValueRepo.kt @@ -0,0 +1,72 @@ +package dev.inmo.micro_utils.repos.exposed.keyvalue + +import dev.inmo.micro_utils.repos.KeyValueRepo +import kotlinx.coroutines.flow.* +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.statements.InsertStatement +import org.jetbrains.exposed.sql.statements.UpdateStatement +import org.jetbrains.exposed.sql.transactions.transaction + +abstract class AbstractExposedKeyValueRepo( + override val database: Database, + tableName: String? = null +) : KeyValueRepo, AbstractExposedReadKeyValueRepo( + database, + tableName +) { + protected val _onNewValue = MutableSharedFlow>() + protected val _onValueRemoved = MutableSharedFlow() + + override val onNewValue: Flow> = _onNewValue.asSharedFlow() + override val onValueRemoved: Flow = _onValueRemoved.asSharedFlow() + + protected abstract fun update(k: Key, v: Value, it: UpdateStatement) + protected abstract fun insert(k: Key, v: Value, it: InsertStatement) + + override suspend fun set(toSet: Map) { + transaction(database) { + toSet.mapNotNull { (k, v) -> + if (update({ selectById(k) }) { update(k, v, it) } > 0) { + k to v + } else { + val inserted = insert { + insert(k, v, it) + }.getOrNull(keyColumn) != null + if (inserted) { + k to v + } else { + null + } + } + } + }.forEach { + _onNewValue.emit(it) + } + } + + override suspend fun unset(toUnset: List) { + transaction(database) { + toUnset.mapNotNull { + if (deleteWhere { selectById(it) } > 0) { + it + } else { + null + } + } + }.forEach { + _onValueRemoved.emit(it) + } + } + + override suspend fun unsetWithValues(toUnset: List) { + transaction(database) { + toUnset.flatMap { + val keys = select { selectByValue(it) }.mapNotNull { it.asKey } + deleteWhere { selectByIds(keys) } + keys + } + }.distinct().forEach { + _onValueRemoved.emit(it) + } + } +} diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/AbstractExposedReadKeyValueRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/AbstractExposedReadKeyValueRepo.kt new file mode 100644 index 00000000000..60c142f7a8f --- /dev/null +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/AbstractExposedReadKeyValueRepo.kt @@ -0,0 +1,60 @@ +package dev.inmo.micro_utils.repos.exposed.keyvalue + +import dev.inmo.micro_utils.pagination.* +import dev.inmo.micro_utils.repos.ReadKeyValueRepo +import dev.inmo.micro_utils.repos.exposed.* +import dev.inmo.micro_utils.repos.exposed.utils.selectPaginated +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq +import org.jetbrains.exposed.sql.transactions.transaction + +abstract class AbstractExposedReadKeyValueRepo( + override val database: Database, + tableName: String? = null +) : ReadKeyValueRepo, + CommonExposedRepo, + Table(tableName ?: "") { + abstract val keyColumn: Column<*> + abstract val ResultRow.asKey: Key + abstract val selectByValue: SqlExpressionBuilder.(Value) -> Op + + override suspend fun get(k: Key): Value? = transaction(database) { + select { selectById(k) }.limit(1).firstOrNull() ?.asObject + } + + override suspend fun contains(key: Key): Boolean = transaction(database) { + select { selectById(key) }.limit(1).any() + } + + override suspend fun count(): Long = transaction(database) { selectAll().count() } + + override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult = transaction(database) { + selectAll().selectPaginated( + pagination, + keyColumn, + reversed + ) { + it.asKey + } + } + + override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult = transaction(database) { + select { selectByValue(v) }.selectPaginated( + pagination, + keyColumn, + reversed + ) { + it.asKey + } + } + + override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult = transaction(database) { + selectAll().selectPaginated( + pagination, + keyColumn, + reversed + ) { + it.asObject + } + } +} diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/ExposedReadKeyValueRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/ExposedReadKeyValueRepo.kt index 7fa979d4a26..fe52ac4de69 100644 --- a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/ExposedReadKeyValueRepo.kt +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/ExposedReadKeyValueRepo.kt @@ -3,7 +3,9 @@ package dev.inmo.micro_utils.repos.exposed.keyvalue import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.repos.ReadKeyValueRepo import dev.inmo.micro_utils.repos.exposed.* +import dev.inmo.micro_utils.repos.exposed.utils.selectPaginated import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.transactions.transaction open class ExposedReadKeyValueRepo( diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedKeyValueRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedKeyValueRepo.kt new file mode 100644 index 00000000000..dd7b319cf9b --- /dev/null +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedKeyValueRepo.kt @@ -0,0 +1,69 @@ +package dev.inmo.micro_utils.repos.exposed.onetomany + +import dev.inmo.micro_utils.repos.KeyValuesRepo +import kotlinx.coroutines.flow.* +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.statements.InsertStatement +import org.jetbrains.exposed.sql.transactions.transaction + +abstract class AbstractExposedKeyValuesRepo( + override val database: Database, + tableName: String? = null +) : KeyValuesRepo, AbstractExposedReadKeyValuesRepo( + database, + tableName +) { + protected val _onNewValue: MutableSharedFlow> = MutableSharedFlow() + override val onNewValue: Flow> + get() = _onNewValue + protected val _onValueRemoved: MutableSharedFlow> = MutableSharedFlow() + override val onValueRemoved: Flow> + get() = _onValueRemoved + protected val _onDataCleared: MutableSharedFlow = MutableSharedFlow() + override val onDataCleared: Flow + get() = _onDataCleared + + protected abstract fun insert(k: Key, v: Value, it: InsertStatement) + + override suspend fun add(toAdd: Map>) { + transaction(database) { + toAdd.keys.flatMap { k -> + toAdd[k] ?.mapNotNull { v -> + if (select { selectById(k).and(selectByValue(v)) }.limit(1).any()) { + return@mapNotNull null + } + val insertResult = insert { + insert(k, v, it) + } + if (insertResult.insertedCount > 0) { + k to v + } else { + null + } + } ?: emptyList() + } + }.forEach { _onNewValue.emit(it) } + } + + override suspend fun remove(toRemove: Map>) { + transaction(database) { + toRemove.keys.flatMap { k -> + toRemove[k] ?.mapNotNull { v -> + if (deleteWhere { selectById(k).and(selectByValue(v)) } > 0 ) { + k to v + } else { + null + } + } ?: emptyList() + } + }.forEach { + _onValueRemoved.emit(it) + } + } + + override suspend fun clear(k: Key) { + transaction(database) { + deleteWhere { selectById(k) } + }.also { _onDataCleared.emit(k) } + } +} diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedReadKeyValueRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedReadKeyValueRepo.kt new file mode 100644 index 00000000000..1575c9b0d04 --- /dev/null +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedReadKeyValueRepo.kt @@ -0,0 +1,74 @@ +package dev.inmo.micro_utils.repos.exposed.onetomany + +import dev.inmo.micro_utils.pagination.* +import dev.inmo.micro_utils.repos.ReadKeyValueRepo +import dev.inmo.micro_utils.repos.ReadKeyValuesRepo +import dev.inmo.micro_utils.repos.exposed.* +import dev.inmo.micro_utils.repos.exposed.utils.selectPaginated +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq +import org.jetbrains.exposed.sql.transactions.transaction + +abstract class AbstractExposedReadKeyValuesRepo( + override val database: Database, + tableName: String? = null +) : ReadKeyValuesRepo, + CommonExposedRepo, + Table(tableName ?: "") { + abstract val keyColumn: Column<*> + abstract val ResultRow.asKey: Key + abstract val selectByValue: SqlExpressionBuilder.(Value) -> Op + + override suspend fun count(k: Key): Long = transaction(database) { select { selectById(k) }.count() } + + override suspend fun count(): Long = transaction(database) { selectAll().count() } + + override suspend fun get( + k: Key, + pagination: Pagination, + reversed: Boolean + ): PaginationResult = transaction(database) { + select { selectById(k) }.selectPaginated( + pagination, + keyColumn, + reversed + ) { + it.asObject + } + } + + override suspend fun keys( + pagination: Pagination, + reversed: Boolean + ): PaginationResult = transaction(database) { + selectAll().selectPaginated( + pagination, + keyColumn, + reversed + ) { + it.asKey + } + } + + override suspend fun keys( + v: Value, + pagination: Pagination, + reversed: Boolean + ): PaginationResult = transaction(database) { + select { selectByValue(v) }.selectPaginated( + pagination, + keyColumn, + reversed + ) { + it.asKey + } + } + + override suspend fun contains(k: Key): Boolean = transaction(database) { + select { selectById(k) }.limit(1).any() + } + + override suspend fun contains(k: Key, v: Value): Boolean = transaction(database) { + select { selectById(k).and(selectByValue(v)) }.limit(1).any() + } +} diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/utils/PaginatedSelect.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/utils/PaginatedSelect.kt new file mode 100644 index 00000000000..a1a327e4e07 --- /dev/null +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/utils/PaginatedSelect.kt @@ -0,0 +1,21 @@ +package dev.inmo.micro_utils.repos.exposed.utils + +import dev.inmo.micro_utils.pagination.* +import org.jetbrains.exposed.sql.* + +fun Query.selectPaginated( + pagination: Pagination, + orderBy: Pair, SortOrder>? = null, + createResult: (ResultRow) -> T +): PaginationResult { + val count = count() + val list = paginate(pagination, orderBy).map(createResult) + return list.createPaginationResult(pagination, count) +} + +fun Query.selectPaginated( + pagination: Pagination, + orderBy: Expression<*>?, + reversed: Boolean = false, + createResult: (ResultRow) -> T +) = selectPaginated(pagination, orderBy ?.let { it to if (reversed) SortOrder.DESC else SortOrder.ASC }, createResult) From 2c2b3641674ac821253b90ea3faaf8e5e1a5f319 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 22 Aug 2022 01:25:07 +0600 Subject: [PATCH 3/5] add default unoptimized realization of selectByIds --- .../micro_utils/repos/exposed/CommonExposedRepo.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt index f30da0c9eda..bfce08a36d1 100644 --- a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt @@ -6,4 +6,15 @@ interface CommonExposedRepo : ExposedRepo { val ResultRow.asObject: ObjectType val selectById: SqlExpressionBuilder.(IdType) -> Op val selectByIds: SqlExpressionBuilder.(List) -> Op + get() = { list -> + if (list.isEmpty()) { + Op.FALSE + } else { + var op = selectById(list.first()) + (1 until list.size).forEach { + op = op.and(selectById(list[it])) + } + op + } + } } From 1d01b65b5f1514dd65946d4dca87f64d844622f5 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 22 Aug 2022 01:26:28 +0600 Subject: [PATCH 4/5] fix --- .../dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt index bfce08a36d1..7501646499e 100644 --- a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/CommonExposedRepo.kt @@ -12,7 +12,7 @@ interface CommonExposedRepo : ExposedRepo { } else { var op = selectById(list.first()) (1 until list.size).forEach { - op = op.and(selectById(list[it])) + op = op.or(selectById(list[it])) } op } From fa061f88e295dc71f0a79e702c64904cb1c252a2 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 22 Aug 2022 01:42:04 +0600 Subject: [PATCH 5/5] refactor --- .../repos/exposed/keyvalue/ExposedReadKeyValueRepo.kt | 2 -- .../repos/exposed/onetomany/AbstractExposedKeyValueRepo.kt | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/ExposedReadKeyValueRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/ExposedReadKeyValueRepo.kt index fe52ac4de69..7fa979d4a26 100644 --- a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/ExposedReadKeyValueRepo.kt +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/keyvalue/ExposedReadKeyValueRepo.kt @@ -3,9 +3,7 @@ package dev.inmo.micro_utils.repos.exposed.keyvalue import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.repos.ReadKeyValueRepo import dev.inmo.micro_utils.repos.exposed.* -import dev.inmo.micro_utils.repos.exposed.utils.selectPaginated import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.transactions.transaction open class ExposedReadKeyValueRepo( diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedKeyValueRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedKeyValueRepo.kt index dd7b319cf9b..c4ae2cd684a 100644 --- a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedKeyValueRepo.kt +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/AbstractExposedKeyValueRepo.kt @@ -15,13 +15,13 @@ abstract class AbstractExposedKeyValuesRepo( ) { protected val _onNewValue: MutableSharedFlow> = MutableSharedFlow() override val onNewValue: Flow> - get() = _onNewValue + get() = _onNewValue.asSharedFlow() protected val _onValueRemoved: MutableSharedFlow> = MutableSharedFlow() override val onValueRemoved: Flow> - get() = _onValueRemoved + get() = _onValueRemoved.asSharedFlow() protected val _onDataCleared: MutableSharedFlow = MutableSharedFlow() override val onDataCleared: Flow - get() = _onDataCleared + get() = _onDataCleared.asSharedFlow() protected abstract fun insert(k: Key, v: Value, it: InsertStatement)