From 43f148bf4bc9fedab0038be05f6a3d2e4eda2876 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 30 Jul 2020 19:44:47 +0600 Subject: [PATCH] fixes --- .../exposed/commons/QueryExtensions.kt | 5 + .../repos/exposed/AbstractExposedCRUDRepo.kt | 13 +++ .../exposed/AbstractExposedReadCRUDRepo.kt | 39 +++++++ .../exposed/AbstractExposedWriteCRUDRepo.kt | 105 ++++++++++++++++++ .../utils/repos/exposed/ExposedCRUDRepo.kt | 13 +++ .../exposed/ExposedTableInitialization.kt | 10 ++ .../AbstractOneToManyExposedKeyValueRepo.kt | 34 ++++++ ...bstractOneToManyExposedReadKeyValueRepo.kt | 48 ++++++++ 8 files changed, 267 insertions(+) create mode 100644 postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedCRUDRepo.kt create mode 100644 postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedReadCRUDRepo.kt create mode 100644 postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt create mode 100644 postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/ExposedCRUDRepo.kt create mode 100644 postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/ExposedTableInitialization.kt create mode 100644 postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/onetomany/AbstractOneToManyExposedKeyValueRepo.kt create mode 100644 postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/onetomany/AbstractOneToManyExposedReadKeyValueRepo.kt diff --git a/postssystem.exposed.commons/src/main/kotlin/com/insanusmokrassar/postssystem/exposed/commons/QueryExtensions.kt b/postssystem.exposed.commons/src/main/kotlin/com/insanusmokrassar/postssystem/exposed/commons/QueryExtensions.kt index 03b1caf7..096e0031 100644 --- a/postssystem.exposed.commons/src/main/kotlin/com/insanusmokrassar/postssystem/exposed/commons/QueryExtensions.kt +++ b/postssystem.exposed.commons/src/main/kotlin/com/insanusmokrassar/postssystem/exposed/commons/QueryExtensions.kt @@ -20,3 +20,8 @@ fun Query.paginate(with: Pagination, orderBy: Pair, SortOrder>? = it } } + +fun Query.paginate(with: Pagination, orderBy: Expression<*>?, reversed: Boolean = false) = paginate( + with, + orderBy ?.let { it to if (reversed) SortOrder.DESC else SortOrder.ASC } +) diff --git a/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedCRUDRepo.kt b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedCRUDRepo.kt new file mode 100644 index 00000000..8741bc47 --- /dev/null +++ b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedCRUDRepo.kt @@ -0,0 +1,13 @@ +package com.insanusmokrassar.postssystem.utils.repos.exposed + +import kotlinx.coroutines.channels.Channel + +abstract class AbstractExposedCRUDRepo( + flowsChannelsSize: Int = Channel.BUFFERED, + databaseName: String = "" +) : + AbstractExposedWriteCRUDRepo( + flowsChannelsSize, + databaseName + ), + ExposedCRUDRepo diff --git a/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedReadCRUDRepo.kt b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedReadCRUDRepo.kt new file mode 100644 index 00000000..ca12fb1f --- /dev/null +++ b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedReadCRUDRepo.kt @@ -0,0 +1,39 @@ +package com.insanusmokrassar.postssystem.utils.repos.exposed + +import com.insanusmokrassar.postssystem.exposed.commons.paginate +import com.insanusmokrassar.postssystem.utils.repos.ReadStandardCRUDRepo +import com.insanusmokrassar.postssystem.utils.repos.pagination.* +import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.sql.select +import org.jetbrains.exposed.sql.selectAll +import org.jetbrains.exposed.sql.transactions.transaction + +abstract class AbstractExposedReadCRUDRepo( + tableName: String +) : + ReadStandardCRUDRepo, + ExposedCRUDRepo, + Table(tableName) +{ + override suspend fun getByPagination(pagination: Pagination): PaginationResult { + return transaction(database) { + selectAll().paginate(pagination).map { + it.asObject + }.createPaginationResult( + pagination, + selectAll().count() + ) + } + } + override suspend fun getById(id: IdType): ObjectType? { + return transaction(database) { + select { + selectById(id) + }.limit(1).firstOrNull() ?.asObject + } + } + + override suspend fun contains(id: IdType): Boolean = transaction(database) { + select { selectById(id) }.limit(1).any() + } +} diff --git a/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt new file mode 100644 index 00000000..f8faed4a --- /dev/null +++ b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt @@ -0,0 +1,105 @@ +package com.insanusmokrassar.postssystem.utils.repos.exposed + +import com.insanusmokrassar.postssystem.utils.repos.UpdatedValuePair +import com.insanusmokrassar.postssystem.utils.repos.WriteStandardCRUDRepo +import kotlinx.coroutines.channels.BroadcastChannel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.asFlow +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 AbstractExposedWriteCRUDRepo( + flowsChannelsSize: Int = 64, + databaseName: String = "" +) : + AbstractExposedReadCRUDRepo(databaseName), + ExposedCRUDRepo, + WriteStandardCRUDRepo +{ + protected val newObjectsChannel = BroadcastChannel(flowsChannelsSize) + protected val updateObjectsChannel = BroadcastChannel(flowsChannelsSize) + protected val deleteObjectsIdsChannel = BroadcastChannel(flowsChannelsSize) + + override val newObjectsFlow: Flow = newObjectsChannel.asFlow() + override val updatedObjectsFlow: Flow = updateObjectsChannel.asFlow() + override val deletedObjectsIdsFlow: Flow = deleteObjectsIdsChannel.asFlow() + + abstract val InsertStatement.asObject: ObjectType + abstract val selectByIds: SqlExpressionBuilder.(Array) -> Op + + protected abstract fun insert(value: InputValueType, it: InsertStatement) + protected abstract fun update(id: IdType, value: InputValueType, it: UpdateStatement) + + protected open suspend fun onBeforeCreate(vararg value: InputValueType) {} + private fun createWithoutNotification(value: InputValueType): ObjectType { + return transaction(database) { + insert { insert(value, it) }.asObject + } + } + + override suspend fun create(vararg values: InputValueType): List { + onBeforeCreate(*values) + return transaction(database) { + values.map { value -> createWithoutNotification(value) } + }.also { + it.forEach { + newObjectsChannel.send(it) + } + } + } + + protected open suspend fun onBeforeUpdate(vararg value: UpdatedValuePair) {} + private fun updateWithoutNotification(id: IdType, value: InputValueType): ObjectType? { + return transaction(database) { + update( + { + selectById(this, id) + } + ) { + update(id, value, it) + } + }.let { + if (it > 0) { + select { + selectById(this, id) + }.limit(1).firstOrNull() ?.asObject + } else { + null + } + } + } + + override suspend fun update(id: IdType, value: InputValueType): ObjectType? { + onBeforeUpdate(id to value) + return updateWithoutNotification(id, value).also { + if (it != null) { + updateObjectsChannel.send(it) + } + } + } + override suspend fun update(vararg values: UpdatedValuePair): List { + onBeforeUpdate(*values) + return ( + transaction(database) { + values.map { (id, value) -> updateWithoutNotification(id, value) } + }.filter { + it != null + } as List + ).also { + it.forEach { + updateObjectsChannel.send(it) + } + } + } + protected open suspend fun onBeforeDelete(vararg ids: IdType) {} + override suspend fun deleteById(vararg ids: IdType) { + onBeforeDelete(*ids) + transaction(database) { + deleteWhere(null, null) { + selectByIds(ids) + } + } + } +} \ No newline at end of file diff --git a/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/ExposedCRUDRepo.kt b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/ExposedCRUDRepo.kt new file mode 100644 index 00000000..6f034bb7 --- /dev/null +++ b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/ExposedCRUDRepo.kt @@ -0,0 +1,13 @@ +package com.insanusmokrassar.postssystem.utils.repos.exposed + +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.Op +import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.sql.SqlExpressionBuilder + +interface ExposedCRUDRepo { + val database: Database + + val ResultRow.asObject: ObjectType + val selectById: SqlExpressionBuilder.(IdType) -> Op +} diff --git a/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/ExposedTableInitialization.kt b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/ExposedTableInitialization.kt new file mode 100644 index 00000000..c8bae5f8 --- /dev/null +++ b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/ExposedTableInitialization.kt @@ -0,0 +1,10 @@ +package com.insanusmokrassar.postssystem.utils.repos.exposed + +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.SchemaUtils +import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.sql.transactions.transaction + +fun Table.initTable(database: Database) { + transaction(database) { SchemaUtils.createMissingTablesAndColumns(this@initTable) } +} diff --git a/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/onetomany/AbstractOneToManyExposedKeyValueRepo.kt b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/onetomany/AbstractOneToManyExposedKeyValueRepo.kt new file mode 100644 index 00000000..4a587073 --- /dev/null +++ b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/onetomany/AbstractOneToManyExposedKeyValueRepo.kt @@ -0,0 +1,34 @@ +package com.insanusmokrassar.postssystem.utils.repos.exposed.onetomany + +import com.insanusmokrassar.budgetmanager.core.utils.repo.onetomany.AbstractOneToManyExposedReadKeyValueRepo +import com.insanusmokrassar.budgetmanager.core.utils.repo.onetomany.ColumnAllocator +import com.insanusmokrassar.postssystem.utils.repos.OneToManyKeyValueRepo +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction + +abstract class AbstractOneToManyExposedKeyValueRepo( + keyColumnAllocator: ColumnAllocator, + valueColumnAllocator: ColumnAllocator, + database: Database +) : OneToManyKeyValueRepo, AbstractOneToManyExposedReadKeyValueRepo( + keyColumnAllocator, + valueColumnAllocator, + database +) { + override suspend fun add(k: Key, v: Value) { + transaction(database) { + insert { + it[keyColumn] = k + it[valueColumn] = v + } + } + } + + override suspend fun remove(k: Key, v: Value) { + transaction(database) { deleteWhere { keyColumn.eq(k).and(valueColumn.eq(v)) } } + } + + override suspend fun clear(k: Key) { + transaction(database) { deleteWhere { keyColumn.eq(k) } } + } +} diff --git a/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/onetomany/AbstractOneToManyExposedReadKeyValueRepo.kt b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/onetomany/AbstractOneToManyExposedReadKeyValueRepo.kt new file mode 100644 index 00000000..65161b46 --- /dev/null +++ b/postssystem.utils.repos.exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/onetomany/AbstractOneToManyExposedReadKeyValueRepo.kt @@ -0,0 +1,48 @@ +package com.insanusmokrassar.budgetmanager.core.utils.repo.onetomany + +import com.insanusmokrassar.postssystem.exposed.commons.paginate +import com.insanusmokrassar.postssystem.utils.repos.OneToManyReadKeyValueRepo +import com.insanusmokrassar.postssystem.utils.repos.pagination.* +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction + +typealias ColumnAllocator = Table.() -> Column + +abstract class AbstractOneToManyExposedReadKeyValueRepo( + keyColumnAllocator: ColumnAllocator, + valueColumnAllocator: ColumnAllocator, + protected val database: Database +) : OneToManyReadKeyValueRepo, Table() { + protected val keyColumn: Column = keyColumnAllocator() + protected val valueColumn: Column = valueColumnAllocator() + + 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 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() + } +}