Complete MetaQuery

This commit is contained in:
Syer10
2023-04-08 15:47:10 -04:00
parent 891fb0b479
commit a90e5d13ea
3 changed files with 186 additions and 10 deletions
@@ -9,13 +9,31 @@ package suwayomi.tachidesk.graphql.queries
import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.Op
import org.jetbrains.exposed.sql.SortOrder
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
import org.jetbrains.exposed.sql.andWhere
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.global.model.table.GlobalMetaTable
import suwayomi.tachidesk.graphql.queries.filter.Filter
import suwayomi.tachidesk.graphql.queries.filter.HasGetOp
import suwayomi.tachidesk.graphql.queries.filter.OpAnd
import suwayomi.tachidesk.graphql.queries.filter.StringFilter
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareString
import suwayomi.tachidesk.graphql.queries.filter.applyOps
import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
import suwayomi.tachidesk.graphql.types.GlobalMetaItem
import suwayomi.tachidesk.graphql.types.MetaItem
import suwayomi.tachidesk.graphql.types.MetaNodeList
import suwayomi.tachidesk.graphql.types.MetaNodeList.Companion.toNodeList
import java.util.concurrent.CompletableFuture
/**
@@ -32,11 +50,145 @@ class MetaQuery {
return dataFetchingEnvironment.getValueFromDataLoader<String, MetaItem?>("GlobalMetaDataLoader", key)
}
fun metas(): MetaNodeList {
val results = transaction {
GlobalMetaTable.selectAll().toList()
enum class MetaOrderBy(override val column: Column<out Comparable<*>>) : OrderBy<MetaItem> {
KEY(GlobalMetaTable.key),
VALUE(GlobalMetaTable.value);
override fun greater(cursor: Cursor): Op<Boolean> {
return when (this) {
KEY -> GlobalMetaTable.key greater cursor.value
VALUE -> greaterNotUnique(GlobalMetaTable.value, GlobalMetaTable.key, cursor, String::toString)
}
}
return results.map { GlobalMetaItem(it) }.toNodeList()
override fun less(cursor: Cursor): Op<Boolean> {
return when (this) {
KEY -> GlobalMetaTable.key less cursor.value
VALUE -> lessNotUnique(GlobalMetaTable.value, GlobalMetaTable.key, cursor, String::toString)
}
}
override fun asCursor(type: MetaItem): Cursor {
val value = when (this) {
KEY -> type.key
VALUE -> type.key + "-" + type.value
}
return Cursor(value)
}
}
data class MetaCondition(
val key: String? = null,
val value: String? = null
) : HasGetOp {
override fun getOp(): Op<Boolean>? {
val opAnd = OpAnd()
opAnd.eq(key, GlobalMetaTable.key)
opAnd.eq(value, GlobalMetaTable.value)
return opAnd.op
}
}
data class MetaFilter(
val key: StringFilter? = null,
val value: StringFilter? = null,
override val and: List<MetaFilter>? = null,
override val or: List<MetaFilter>? = null,
override val not: MetaFilter? = null
) : Filter<MetaFilter> {
override fun getOpList(): List<Op<Boolean>> {
return listOfNotNull(
andFilterWithCompareString(GlobalMetaTable.key, key),
andFilterWithCompareString(GlobalMetaTable.value, value)
)
}
}
fun metas(
condition: MetaCondition? = null,
filter: MetaFilter? = null,
orderBy: MetaOrderBy? = null,
orderByType: SortOrder? = null,
before: Cursor? = null,
after: Cursor? = null,
first: Int? = null,
last: Int? = null,
offset: Int? = null
): MetaNodeList {
val queryResults = transaction {
val res = GlobalMetaTable.selectAll()
res.applyOps(condition, filter)
if (orderBy != null || (last != null || before != null)) {
val orderByColumn = orderBy?.column ?: GlobalMetaTable.key
val orderType = orderByType.maybeSwap(last ?: before)
if (orderBy == MetaOrderBy.KEY || orderBy == null) {
res.orderBy(orderByColumn to orderType)
} else {
res.orderBy(
orderByColumn to orderType,
GlobalMetaTable.key to SortOrder.ASC
)
}
}
val total = res.count()
val firstResult = res.firstOrNull()?.get(GlobalMetaTable.key)
val lastResult = res.lastOrNull()?.get(GlobalMetaTable.key)
if (after != null) {
res.andWhere {
(orderBy ?: MetaOrderBy.KEY).greater(after)
}
} else if (before != null) {
res.andWhere {
(orderBy ?: MetaOrderBy.KEY).less(before)
}
}
if (first != null) {
res.limit(first, offset?.toLong() ?: 0)
} else if (last != null) {
res.limit(last)
}
QueryResults(total, firstResult, lastResult, res.toList())
}
val getAsCursor: (MetaItem) -> Cursor = (orderBy ?: MetaOrderBy.KEY)::asCursor
val resultsAsType = queryResults.results.map { GlobalMetaItem(it) }
return MetaNodeList(
resultsAsType,
if (resultsAsType.isEmpty()) {
emptyList()
} else {
listOfNotNull(
resultsAsType.firstOrNull()?.let {
MetaNodeList.MetaEdge(
getAsCursor(it),
it
)
},
resultsAsType.lastOrNull()?.let {
MetaNodeList.MetaEdge(
getAsCursor(it),
it
)
}
)
},
pageInfo = PageInfo(
hasNextPage = queryResults.lastKey != resultsAsType.lastOrNull()?.key,
hasPreviousPage = queryResults.firstKey != resultsAsType.firstOrNull()?.key,
startCursor = resultsAsType.firstOrNull()?.let { getAsCursor(it) },
endCursor = resultsAsType.lastOrNull()?.let { getAsCursor(it) }
),
totalCount = queryResults.total.toInt()
)
}
}
@@ -36,14 +36,38 @@ fun SortOrder?.maybeSwap(value: Any?): SortOrder {
}
}
fun <T: Comparable<T>> greaterNotUnique(column: Column<T>, idColumn: Column<EntityID<Int>>, cursor: Cursor, toValue: (String) -> T): Op<Boolean> {
fun <T : Comparable<T>> greaterNotUnique(column: Column<T>, idColumn: Column<EntityID<Int>>, cursor: Cursor, toValue: (String) -> T): Op<Boolean> {
val id = cursor.value.substringBefore('-').toInt()
val value = toValue(cursor.value.substringAfter('-'))
return (column greater value) or ((column eq value) and (idColumn greater id))
}
fun <T: Comparable<T>> lessNotUnique(column: Column<T>, idColumn: Column<EntityID<Int>>, cursor: Cursor, toValue: (String) -> T): Op<Boolean> {
@JvmName("greaterNotUniqueStringKey")
fun <T : Comparable<T>> greaterNotUnique(
column: Column<T>,
idColumn: Column<String>,
cursor: Cursor,
toValue: (String) -> T
): Op<Boolean> {
val id = cursor.value.substringBefore('-')
val value = toValue(cursor.value.substringAfter('-'))
return (column greater value) or ((column eq value) and (idColumn greater id))
}
fun <T : Comparable<T>> lessNotUnique(column: Column<T>, idColumn: Column<EntityID<Int>>, cursor: Cursor, toValue: (String) -> T): Op<Boolean> {
val id = cursor.value.substringBefore('-').toInt()
val value = toValue(cursor.value.substringAfter('-'))
return (column less value) or ((column eq value) and (idColumn less id))
}
}
@JvmName("lessNotUniqueStringKey")
fun <T : Comparable<T>> lessNotUnique(
column: Column<T>,
idColumn: Column<String>,
cursor: Cursor,
toValue: (String) -> T
): Op<Boolean> {
val id = cursor.value.substringBefore('-')
val value = toValue(cursor.value.substringAfter('-'))
return (column less value) or ((column eq value) and (idColumn less id))
}
@@ -37,8 +37,8 @@ class MangaType(
val inLibrary: Boolean,
val inLibraryAt: Long,
val realUrl: String?,
var lastFetchedAt: Long?, //todo
var chaptersLastFetchedAt: Long? //todo
var lastFetchedAt: Long?, // todo
var chaptersLastFetchedAt: Long? // todo
) : Node {
constructor(row: ResultRow) : this(
row[MangaTable.id].value,