fixes
This commit is contained in:
parent
3baf6cc3c6
commit
43f148bf4b
@ -20,3 +20,8 @@ fun Query.paginate(with: Pagination, orderBy: Pair<Expression<*>, SortOrder>? =
|
|||||||
it
|
it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Query.paginate(with: Pagination, orderBy: Expression<*>?, reversed: Boolean = false) = paginate(
|
||||||
|
with,
|
||||||
|
orderBy ?.let { it to if (reversed) SortOrder.DESC else SortOrder.ASC }
|
||||||
|
)
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.insanusmokrassar.postssystem.utils.repos.exposed
|
||||||
|
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
|
||||||
|
abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||||
|
flowsChannelsSize: Int = Channel.BUFFERED,
|
||||||
|
databaseName: String = ""
|
||||||
|
) :
|
||||||
|
AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||||
|
flowsChannelsSize,
|
||||||
|
databaseName
|
||||||
|
),
|
||||||
|
ExposedCRUDRepo<ObjectType, IdType>
|
@ -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<ObjectType, IdType>(
|
||||||
|
tableName: String
|
||||||
|
) :
|
||||||
|
ReadStandardCRUDRepo<ObjectType, IdType>,
|
||||||
|
ExposedCRUDRepo<ObjectType, IdType>,
|
||||||
|
Table(tableName)
|
||||||
|
{
|
||||||
|
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
@ -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<ObjectType, IdType, InputValueType>(
|
||||||
|
flowsChannelsSize: Int = 64,
|
||||||
|
databaseName: String = ""
|
||||||
|
) :
|
||||||
|
AbstractExposedReadCRUDRepo<ObjectType, IdType>(databaseName),
|
||||||
|
ExposedCRUDRepo<ObjectType, IdType>,
|
||||||
|
WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>
|
||||||
|
{
|
||||||
|
protected val newObjectsChannel = BroadcastChannel<ObjectType>(flowsChannelsSize)
|
||||||
|
protected val updateObjectsChannel = BroadcastChannel<ObjectType>(flowsChannelsSize)
|
||||||
|
protected val deleteObjectsIdsChannel = BroadcastChannel<IdType>(flowsChannelsSize)
|
||||||
|
|
||||||
|
override val newObjectsFlow: Flow<ObjectType> = newObjectsChannel.asFlow()
|
||||||
|
override val updatedObjectsFlow: Flow<ObjectType> = updateObjectsChannel.asFlow()
|
||||||
|
override val deletedObjectsIdsFlow: Flow<IdType> = deleteObjectsIdsChannel.asFlow()
|
||||||
|
|
||||||
|
abstract val InsertStatement<Number>.asObject: ObjectType
|
||||||
|
abstract val selectByIds: SqlExpressionBuilder.(Array<out IdType>) -> Op<Boolean>
|
||||||
|
|
||||||
|
protected abstract fun insert(value: InputValueType, it: InsertStatement<Number>)
|
||||||
|
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<ObjectType> {
|
||||||
|
onBeforeCreate(*values)
|
||||||
|
return transaction(database) {
|
||||||
|
values.map { value -> createWithoutNotification(value) }
|
||||||
|
}.also {
|
||||||
|
it.forEach {
|
||||||
|
newObjectsChannel.send(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open suspend fun onBeforeUpdate(vararg value: UpdatedValuePair<IdType, InputValueType>) {}
|
||||||
|
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<IdType, InputValueType>): List<ObjectType> {
|
||||||
|
onBeforeUpdate(*values)
|
||||||
|
return (
|
||||||
|
transaction(database) {
|
||||||
|
values.map { (id, value) -> updateWithoutNotification(id, value) }
|
||||||
|
}.filter {
|
||||||
|
it != null
|
||||||
|
} as List<ObjectType>
|
||||||
|
).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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<ObjectType, IdType> {
|
||||||
|
val database: Database
|
||||||
|
|
||||||
|
val ResultRow.asObject: ObjectType
|
||||||
|
val selectById: SqlExpressionBuilder.(IdType) -> Op<Boolean>
|
||||||
|
}
|
@ -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) }
|
||||||
|
}
|
@ -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<Key, Value>(
|
||||||
|
keyColumnAllocator: ColumnAllocator<Key>,
|
||||||
|
valueColumnAllocator: ColumnAllocator<Value>,
|
||||||
|
database: Database
|
||||||
|
) : OneToManyKeyValueRepo<Key, Value>, AbstractOneToManyExposedReadKeyValueRepo<Key, Value>(
|
||||||
|
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) } }
|
||||||
|
}
|
||||||
|
}
|
@ -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<T> = Table.() -> Column<T>
|
||||||
|
|
||||||
|
abstract class AbstractOneToManyExposedReadKeyValueRepo<Key, Value>(
|
||||||
|
keyColumnAllocator: ColumnAllocator<Key>,
|
||||||
|
valueColumnAllocator: ColumnAllocator<Value>,
|
||||||
|
protected val database: Database
|
||||||
|
) : OneToManyReadKeyValueRepo<Key, Value>, Table() {
|
||||||
|
protected val keyColumn: Column<Key> = keyColumnAllocator()
|
||||||
|
protected val valueColumn: Column<Value> = 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<Value> = 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<Key> = 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()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user