From 1257492f85da63e3fcb2cd90f9432ac0c019de4d Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 11 Oct 2022 12:55:25 +0600 Subject: [PATCH] changes in insert/update exposed methods and rewriting of read keyvalue(s) exposed repos to be extending abstract key value(s) repos --- CHANGELOG.md | 9 +++ .../exposed/AbstractExposedWriteCRUDRepo.kt | 50 ++++++++++++---- .../keyvalue/AbstractExposedKeyValueRepo.kt | 23 ++++++-- .../keyvalue/ExposedReadKeyValueRepo.kt | 58 +++++-------------- .../onetomany/ExposedReadKeyValuesRepo.kt | 57 +++--------------- 5 files changed, 89 insertions(+), 108 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8303d735c6d..e302bb016a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ ## 0.13.0 +* `Repos`: + * `Exposed`: + * `AbstractExposedWriteCRUDRepo` got two new methods: `update` with `it` as `UpdateBuilder` and `createAndInsertId` + * Old `update` method has been deprecated and not recommended to override anymore in realizations + * Old `insert` method now is `open` instead of `abstract` and can be omitted + * `AbstractExposedKeyValueRepo` got two new methods: `update` with `it` as `UpdateBuilder` and `insertKey` + * Old `update` method has been deprecated and not recommended to override anymore + * Old `insert` method now is `open` instead of `abstract` and can be omitted in realizations + ## 0.12.17 * `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 6bb44a53052..1440b5cfaf1 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 @@ -4,9 +4,9 @@ import dev.inmo.micro_utils.repos.UpdatedValuePair import dev.inmo.micro_utils.repos.WriteCRUDRepo 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.statements.* import org.jetbrains.exposed.sql.transactions.transaction +import java.util.Objects abstract class AbstractExposedWriteCRUDRepo( flowsChannelsSize: Int = 0, @@ -27,10 +27,31 @@ abstract class AbstractExposedWriteCRUDRepo( protected abstract fun InsertStatement.asObject(value: InputValueType): ObjectType - protected abstract fun insert(value: InputValueType, it: InsertStatement) - protected abstract fun update(id: IdType, value: InputValueType, it: UpdateStatement) + protected abstract fun update(id: IdType, value: InputValueType, it: UpdateBuilder) + protected abstract fun createAndInsertId(value: InputValueType, it: InsertStatement): IdType + + protected open fun insert(value: InputValueType, it: InsertStatement) { + val id = createAndInsertId(value, it) + update(id, value, it as UpdateBuilder) + } + @Deprecated( + "Replace its \"it\" parameter type with \"UpdateBuilder\" to actualize method signature. Method with current signature will be removed soon and do not recommended to override anymore" + ) + protected open fun update(id: IdType, value: InputValueType, it: UpdateStatement) = update( + id, + value, + it as UpdateBuilder + ) protected open suspend fun onBeforeCreate(value: List) {} + + /** + * Use this method to do the something with [values]. You may change and output values in that list and return + * changed list of pairs + */ + protected open suspend fun onAfterCreate( + values: List> + ): List = values.map { it.second } private fun createWithoutNotification(value: InputValueType): ObjectType { return transaction(database) { insert { insert(value, it) }.asObject(value) @@ -40,13 +61,18 @@ abstract class AbstractExposedWriteCRUDRepo( override suspend fun create(values: List): List { onBeforeCreate(values) return transaction(db = database) { - values.map { value -> createWithoutNotification(value) } + values.map { value -> value to createWithoutNotification(value) } + }.let { + onAfterCreate(it) }.onEach { _newObjectsFlow.emit(it) } } protected open suspend fun onBeforeUpdate(value: List>) {} + protected open suspend fun onAfterUpdate( + value: List> + ): List = value.map { it.second } private fun updateWithoutNotification(id: IdType, value: InputValueType): ObjectType? { return transaction(db = database) { update( @@ -54,7 +80,7 @@ abstract class AbstractExposedWriteCRUDRepo( selectById(this, id) } ) { - update(id, value, it) + update(id, value, it as UpdateBuilder) } }.let { if (it > 0) { @@ -71,7 +97,9 @@ abstract class AbstractExposedWriteCRUDRepo( override suspend fun update(id: IdType, value: InputValueType): ObjectType? { onBeforeUpdate(listOf(id to value)) - return updateWithoutNotification(id, value).also { + return updateWithoutNotification(id, value).let { + onAfterUpdate(listOf(value to (it ?: return@let emptyList()))) + }.firstOrNull().also { if (it != null) { _updatedObjectsFlow.emit(it) } @@ -81,9 +109,11 @@ abstract class AbstractExposedWriteCRUDRepo( onBeforeUpdate(values) return ( transaction(db = database) { - values.map { (id, value) -> updateWithoutNotification(id, value) } - }.filterNotNull() - ).onEach { + values.mapNotNull { (id, value) -> value to (updateWithoutNotification(id, value) ?: return@mapNotNull null) } + } + ).let { + onAfterUpdate(it) + }.onEach { _updatedObjectsFlow.emit(it) } } 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 index 528c669ec8b..42a640ef648 100644 --- 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 @@ -3,8 +3,7 @@ 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.statements.* import org.jetbrains.exposed.sql.transactions.transaction abstract class AbstractExposedKeyValueRepo( @@ -20,13 +19,27 @@ abstract class AbstractExposedKeyValueRepo( 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) + protected abstract fun update(k: Key, v: Value, it: UpdateBuilder) + protected abstract fun insertKey(k: Key, v: Value, it: InsertStatement) + + protected open fun insert(k: Key, v: Value, it: InsertStatement) { + insertKey(k, v, it) + update(k, v, it as UpdateBuilder) + } + + @Deprecated( + "Replace its \"it\" parameter type with \"UpdateBuilder\" to actualize method signature. Method with current signature will be removed soon and do not recommended to override anymore" + ) + protected open fun update(k: Key, v: Value, it: UpdateStatement) = update( + k, + v, + it as UpdateBuilder + ) override suspend fun set(toSet: Map) { transaction(database) { toSet.mapNotNull { (k, v) -> - if (update({ selectById(k) }) { update(k, v, it) } > 0) { + if (update({ selectById(k) }) { update(k, v, it as UpdateBuilder) } > 0) { k to v } else { val inserted = insert { 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 5ea319f8d02..0e01f00b759 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 @@ -5,57 +5,27 @@ 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.statements.InsertStatement +import org.jetbrains.exposed.sql.statements.UpdateBuilder import org.jetbrains.exposed.sql.transactions.transaction open class ExposedReadKeyValueRepo( - override val database: Database, + database: Database, keyColumnAllocator: ColumnAllocator, valueColumnAllocator: ColumnAllocator, tableName: String? = null -) : ReadKeyValueRepo, ExposedRepo, Table(tableName ?: "") { - val keyColumn: Column = keyColumnAllocator() +) : ReadKeyValueRepo, ExposedRepo, AbstractExposedReadKeyValueRepo(database, tableName) { + + override val keyColumn: Column = keyColumnAllocator() val valueColumn: Column = valueColumnAllocator() - override val primaryKey: PrimaryKey = PrimaryKey(keyColumn, valueColumn) + override val ResultRow.asKey: Key + get() = get(keyColumn) + override val selectByValue: SqlExpressionBuilder.(Value) -> Op = { valueColumn.eq(it) } + override val ResultRow.asObject: Value + get() = get(valueColumn) + override val selectById: SqlExpressionBuilder.(Key) -> Op = { keyColumn.eq(it) } + override val primaryKey: Table.PrimaryKey + get() = PrimaryKey(keyColumn, valueColumn) init { initTable() } - - override suspend fun get(k: Key): Value? = transaction(database) { - select { keyColumn.eq(k) }.limit(1).firstOrNull() ?.getOrNull(valueColumn) - } - - override suspend fun contains(key: Key): Boolean = transaction(database) { - select { keyColumn.eq(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[keyColumn] - } - } - - override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult = transaction(database) { - select { valueColumn.eq(v) }.selectPaginated( - pagination, - keyColumn, - reversed - ) { - it[keyColumn] - } - } - - override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult = transaction(database) { - selectAll().selectPaginated( - pagination, - keyColumn, - reversed - ) { - it[valueColumn] - } - } } diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/ExposedReadKeyValuesRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/ExposedReadKeyValuesRepo.kt index d6903b764b3..cb7a6334285 100644 --- a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/ExposedReadKeyValuesRepo.kt +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/onetomany/ExposedReadKeyValuesRepo.kt @@ -1,10 +1,8 @@ package dev.inmo.micro_utils.repos.exposed.onetomany -import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.repos.ReadKeyValuesRepo import dev.inmo.micro_utils.repos.exposed.* import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.transactions.transaction typealias ExposedReadOneToManyKeyValueRepo = ExposedReadKeyValuesRepo @@ -13,54 +11,15 @@ open class ExposedReadKeyValuesRepo( keyColumnAllocator: ColumnAllocator, valueColumnAllocator: ColumnAllocator, tableName: String? = null -) : ReadKeyValuesRepo, ExposedRepo, Table(tableName ?: "") { - val keyColumn: Column = keyColumnAllocator() +) : ReadKeyValuesRepo, ExposedRepo, AbstractExposedReadKeyValuesRepo(database, tableName) { + override val keyColumn: Column = keyColumnAllocator() + override val ResultRow.asKey: Key + get() = get(keyColumn) + override val selectByValue: SqlExpressionBuilder.(Value) -> Op = { valueColumn.eq(it) } + override val ResultRow.asObject: Value + get() = get(valueColumn) + override val selectById: SqlExpressionBuilder.(Key) -> Op = { keyColumn.eq(it) } val valueColumn: Column = valueColumnAllocator() init { initTable() } - - override suspend fun count(k: Key): Long = transaction(database) { select { keyColumn.eq(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 { keyColumn.eq(k) }.paginate(pagination, keyColumn, reversed).map { it[valueColumn] } - }.createPaginationResult( - pagination, - count(k) - ) - - override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult = transaction(database) { - selectAll().paginate(pagination, keyColumn, reversed).map { it[keyColumn] } - }.createPaginationResult( - pagination, - count() - ) - - override suspend fun keys( - v: Value, - pagination: Pagination, - reversed: Boolean - ): PaginationResult = transaction(database) { - select { valueColumn.eq(v) }.let { - it.count() to it.paginate(pagination, keyColumn, reversed).map { it[keyColumn] } - } - }.let { (count, list) -> - list.createPaginationResult( - pagination, - count - ) - } - - override suspend fun contains(k: Key): Boolean = transaction(database) { - select { keyColumn.eq(k) }.limit(1).any() - } - - override suspend fun contains(k: Key, v: Value): Boolean = transaction(database) { - select { keyColumn.eq(k).and(valueColumn.eq(v)) }.limit(1).any() - } }