selectPaginated and abstract exposed keyvalue(s) repos

This commit is contained in:
InsanusMokrassar 2022-08-22 01:11:09 +06:00
parent 193d22ff20
commit 7c5fc9bf7c
10 changed files with 313 additions and 5 deletions

View File

@ -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`:

View File

@ -26,7 +26,6 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
override val deletedObjectsIdsFlow: Flow<IdType> = _deletedObjectsIdsFlow.asSharedFlow()
protected abstract fun InsertStatement<Number>.asObject(value: InputValueType): ObjectType
abstract val selectByIds: SqlExpressionBuilder.(List<IdType>) -> Op<Boolean>
protected abstract fun insert(value: InputValueType, it: InsertStatement<Number>)
protected abstract fun update(id: IdType, value: InputValueType, it: UpdateStatement)

View File

@ -0,0 +1,9 @@
package dev.inmo.micro_utils.repos.exposed
import org.jetbrains.exposed.sql.*
interface CommonExposedRepo<IdType, ObjectType> : ExposedRepo {
val ResultRow.asObject: ObjectType
val selectById: SqlExpressionBuilder.(IdType) -> Op<Boolean>
val selectByIds: SqlExpressionBuilder.(List<IdType>) -> Op<Boolean>
}

View File

@ -2,7 +2,4 @@ package dev.inmo.micro_utils.repos.exposed
import org.jetbrains.exposed.sql.*
interface ExposedCRUDRepo<ObjectType, IdType> : ExposedRepo {
val ResultRow.asObject: ObjectType
val selectById: SqlExpressionBuilder.(IdType) -> Op<Boolean>
}
interface ExposedCRUDRepo<ObjectType, IdType> : CommonExposedRepo<IdType, ObjectType>

View File

@ -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<Key, Value>(
override val database: Database,
tableName: String? = null
) : KeyValueRepo<Key, Value>, AbstractExposedReadKeyValueRepo<Key, Value>(
database,
tableName
) {
protected val _onNewValue = MutableSharedFlow<Pair<Key, Value>>()
protected val _onValueRemoved = MutableSharedFlow<Key>()
override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow()
override val onValueRemoved: Flow<Key> = _onValueRemoved.asSharedFlow()
protected abstract fun update(k: Key, v: Value, it: UpdateStatement)
protected abstract fun insert(k: Key, v: Value, it: InsertStatement<Number>)
override suspend fun set(toSet: Map<Key, Value>) {
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<Key>) {
transaction(database) {
toUnset.mapNotNull {
if (deleteWhere { selectById(it) } > 0) {
it
} else {
null
}
}
}.forEach {
_onValueRemoved.emit(it)
}
}
override suspend fun unsetWithValues(toUnset: List<Value>) {
transaction(database) {
toUnset.flatMap {
val keys = select { selectByValue(it) }.mapNotNull { it.asKey }
deleteWhere { selectByIds(keys) }
keys
}
}.distinct().forEach {
_onValueRemoved.emit(it)
}
}
}

View File

@ -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<Key, Value>(
override val database: Database,
tableName: String? = null
) : ReadKeyValueRepo<Key, Value>,
CommonExposedRepo<Key, Value>,
Table(tableName ?: "") {
abstract val keyColumn: Column<*>
abstract val ResultRow.asKey: Key
abstract val selectByValue: SqlExpressionBuilder.(Value) -> Op<Boolean>
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<Key> = transaction(database) {
selectAll().selectPaginated(
pagination,
keyColumn,
reversed
) {
it.asKey
}
}
override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> = transaction(database) {
select { selectByValue(v) }.selectPaginated(
pagination,
keyColumn,
reversed
) {
it.asKey
}
}
override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> = transaction(database) {
selectAll().selectPaginated(
pagination,
keyColumn,
reversed
) {
it.asObject
}
}
}

View File

@ -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<Key, Value>(

View File

@ -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<Key, Value>(
override val database: Database,
tableName: String? = null
) : KeyValuesRepo<Key, Value>, AbstractExposedReadKeyValuesRepo<Key, Value>(
database,
tableName
) {
protected val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
override val onNewValue: Flow<Pair<Key, Value>>
get() = _onNewValue
protected val _onValueRemoved: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
override val onValueRemoved: Flow<Pair<Key, Value>>
get() = _onValueRemoved
protected val _onDataCleared: MutableSharedFlow<Key> = MutableSharedFlow()
override val onDataCleared: Flow<Key>
get() = _onDataCleared
protected abstract fun insert(k: Key, v: Value, it: InsertStatement<Number>)
override suspend fun add(toAdd: Map<Key, List<Value>>) {
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<Key, List<Value>>) {
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) }
}
}

View File

@ -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<Key, Value>(
override val database: Database,
tableName: String? = null
) : ReadKeyValuesRepo<Key, Value>,
CommonExposedRepo<Key, Value>,
Table(tableName ?: "") {
abstract val keyColumn: Column<*>
abstract val ResultRow.asKey: Key
abstract val selectByValue: SqlExpressionBuilder.(Value) -> Op<Boolean>
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<Value> = transaction(database) {
select { selectById(k) }.selectPaginated(
pagination,
keyColumn,
reversed
) {
it.asObject
}
}
override suspend fun keys(
pagination: Pagination,
reversed: Boolean
): PaginationResult<Key> = transaction(database) {
selectAll().selectPaginated(
pagination,
keyColumn,
reversed
) {
it.asKey
}
}
override suspend fun keys(
v: Value,
pagination: Pagination,
reversed: Boolean
): PaginationResult<Key> = 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()
}
}

View File

@ -0,0 +1,21 @@
package dev.inmo.micro_utils.repos.exposed.utils
import dev.inmo.micro_utils.pagination.*
import org.jetbrains.exposed.sql.*
fun <T> Query.selectPaginated(
pagination: Pagination,
orderBy: Pair<Expression<*>, SortOrder>? = null,
createResult: (ResultRow) -> T
): PaginationResult<T> {
val count = count()
val list = paginate(pagination, orderBy).map(createResult)
return list.createPaginationResult(pagination, count)
}
fun <T> 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)