mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-03 19:04:39 -05:00
Complete CategoryQuery
This commit is contained in:
@@ -9,12 +9,26 @@ package suwayomi.tachidesk.graphql.queries
|
|||||||
|
|
||||||
import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
|
import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
|
||||||
import graphql.schema.DataFetchingEnvironment
|
import graphql.schema.DataFetchingEnvironment
|
||||||
|
import org.jetbrains.exposed.dao.id.EntityID
|
||||||
|
import org.jetbrains.exposed.sql.Column
|
||||||
|
import org.jetbrains.exposed.sql.Op
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
import org.jetbrains.exposed.sql.SortOrder
|
||||||
import org.jetbrains.exposed.sql.andWhere
|
import org.jetbrains.exposed.sql.andWhere
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
||||||
|
import suwayomi.tachidesk.graphql.queries.filter.Filter
|
||||||
|
import suwayomi.tachidesk.graphql.queries.filter.IntFilter
|
||||||
|
import suwayomi.tachidesk.graphql.queries.filter.OpAnd
|
||||||
|
import suwayomi.tachidesk.graphql.queries.filter.StringFilter
|
||||||
|
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompare
|
||||||
|
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareEntity
|
||||||
|
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareString
|
||||||
|
import suwayomi.tachidesk.graphql.queries.filter.getOp
|
||||||
|
import suwayomi.tachidesk.graphql.server.primitives.Cursor
|
||||||
|
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
||||||
|
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
||||||
import suwayomi.tachidesk.graphql.types.CategoryNodeList
|
import suwayomi.tachidesk.graphql.types.CategoryNodeList
|
||||||
import suwayomi.tachidesk.graphql.types.CategoryNodeList.Companion.toNodeList
|
|
||||||
import suwayomi.tachidesk.graphql.types.CategoryType
|
import suwayomi.tachidesk.graphql.types.CategoryType
|
||||||
import suwayomi.tachidesk.manga.model.table.CategoryTable
|
import suwayomi.tachidesk.manga.model.table.CategoryTable
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
@@ -37,43 +51,157 @@ class CategoryQuery {
|
|||||||
return dataFetchingEnvironment.getValueFromDataLoader("CategoryDataLoader", id)
|
return dataFetchingEnvironment.getValueFromDataLoader("CategoryDataLoader", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class CategorySort {
|
enum class CategoryOrderBy {
|
||||||
ID,
|
ID,
|
||||||
NAME,
|
NAME,
|
||||||
ORDER
|
ORDER
|
||||||
}
|
}
|
||||||
|
|
||||||
data class CategoriesQueryInput(
|
private fun getAsCursor(orderBy: CategoryOrderBy?, type: CategoryType): Cursor {
|
||||||
val sort: CategorySort? = null,
|
val value = when (orderBy) {
|
||||||
val sortOrder: SortOrder? = null,
|
CategoryOrderBy.ID, null -> type.id.toString()
|
||||||
val ids: List<Int>? = null,
|
CategoryOrderBy.NAME -> type.name
|
||||||
val query: String? = null
|
CategoryOrderBy.ORDER -> type.order.toString()
|
||||||
)
|
}
|
||||||
|
return Cursor(value)
|
||||||
|
}
|
||||||
|
|
||||||
fun categories(input: CategoriesQueryInput? = null): CategoryNodeList {
|
data class CategoryCondition(
|
||||||
val results = transaction {
|
val id: Int? = null,
|
||||||
|
val order: Int? = null,
|
||||||
|
val name: String? = null,
|
||||||
|
val default: Boolean? = null
|
||||||
|
) {
|
||||||
|
fun getOp(): Op<Boolean>? {
|
||||||
|
val opAnd = OpAnd()
|
||||||
|
fun <T> eq(value: T?, column: Column<T>) = opAnd.andWhere(value) { column eq it }
|
||||||
|
fun <T : Comparable<T>> eq(value: T?, column: Column<EntityID<T>>) = opAnd.andWhere(value) { column eq it }
|
||||||
|
eq(id, CategoryTable.id)
|
||||||
|
eq(order, CategoryTable.order)
|
||||||
|
eq(name, CategoryTable.name)
|
||||||
|
eq(default, CategoryTable.isDefault)
|
||||||
|
|
||||||
|
return opAnd.op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class CategoryFilter(
|
||||||
|
val id: IntFilter? = null,
|
||||||
|
val order: IntFilter? = null,
|
||||||
|
val name: StringFilter? = null,
|
||||||
|
val default: BooleanFilter? = null,
|
||||||
|
override val and: List<CategoryFilter>? = null,
|
||||||
|
override val or: List<CategoryFilter>? = null,
|
||||||
|
override val not: CategoryFilter? = null
|
||||||
|
) : Filter<CategoryFilter> {
|
||||||
|
override fun getOpList(): List<Op<Boolean>> {
|
||||||
|
return listOfNotNull(
|
||||||
|
andFilterWithCompareEntity(CategoryTable.id, id),
|
||||||
|
andFilterWithCompare(CategoryTable.order, order),
|
||||||
|
andFilterWithCompareString(CategoryTable.name, name),
|
||||||
|
andFilterWithCompare(CategoryTable.isDefault, default),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun categories(
|
||||||
|
condition: CategoryCondition? = null,
|
||||||
|
filter: CategoryFilter? = null,
|
||||||
|
orderBy: CategoryOrderBy? = null,
|
||||||
|
orderByType: SortOrder? = null,
|
||||||
|
before: Cursor? = null,
|
||||||
|
after: Cursor? = null,
|
||||||
|
first: Int? = null,
|
||||||
|
last: Int? = null,
|
||||||
|
offset: Int? = null
|
||||||
|
): CategoryNodeList {
|
||||||
|
val queryResults = transaction {
|
||||||
val res = CategoryTable.selectAll()
|
val res = CategoryTable.selectAll()
|
||||||
|
|
||||||
if (input != null) {
|
val conditionOp = condition?.getOp()
|
||||||
if (input.ids != null) {
|
if (conditionOp != null) {
|
||||||
res.andWhere { CategoryTable.id inList input.ids }
|
res.andWhere { conditionOp }
|
||||||
|
}
|
||||||
|
val filterOp = filter?.getOp()
|
||||||
|
if (filterOp != null) {
|
||||||
|
res.andWhere { filterOp }
|
||||||
|
}
|
||||||
|
if (orderBy != null || (last != null || before != null)) {
|
||||||
|
val orderByColumn = when (orderBy) {
|
||||||
|
CategoryOrderBy.ID, null -> CategoryTable.id
|
||||||
|
CategoryOrderBy.NAME -> CategoryTable.name
|
||||||
|
CategoryOrderBy.ORDER -> CategoryTable.order
|
||||||
}
|
}
|
||||||
if (!input.query.isNullOrEmpty()) {
|
val orderType = if (last != null || before != null) {
|
||||||
res.andWhere { CategoryTable.name like input.query }
|
when (orderByType) {
|
||||||
|
SortOrder.ASC -> SortOrder.DESC
|
||||||
|
SortOrder.DESC -> SortOrder.ASC
|
||||||
|
SortOrder.ASC_NULLS_FIRST -> SortOrder.DESC_NULLS_LAST
|
||||||
|
SortOrder.DESC_NULLS_FIRST -> SortOrder.ASC_NULLS_LAST
|
||||||
|
SortOrder.ASC_NULLS_LAST -> SortOrder.DESC_NULLS_FIRST
|
||||||
|
SortOrder.DESC_NULLS_LAST -> SortOrder.ASC_NULLS_FIRST
|
||||||
|
null -> SortOrder.DESC
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
orderByType ?: SortOrder.ASC
|
||||||
}
|
}
|
||||||
val orderBy = when (input.sort) {
|
res.orderBy(orderByColumn, order = orderType)
|
||||||
CategorySort.ID -> CategoryTable.id
|
|
||||||
CategorySort.NAME -> CategoryTable.name
|
|
||||||
CategorySort.ORDER, null -> CategoryTable.order
|
|
||||||
}
|
|
||||||
res.orderBy(orderBy, order = input.sortOrder ?: SortOrder.ASC)
|
|
||||||
} else {
|
|
||||||
res.orderBy(CategoryTable.order)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res.toList()
|
val total = res.count()
|
||||||
|
val firstResult = res.first()[CategoryTable.id].value
|
||||||
|
val lastResult = res.last()[CategoryTable.id].value
|
||||||
|
|
||||||
|
if (after != null) {
|
||||||
|
when (orderBy) {
|
||||||
|
CategoryOrderBy.ID, null -> res.andWhere {
|
||||||
|
CategoryTable.id greater after.value.toInt()
|
||||||
|
}
|
||||||
|
CategoryOrderBy.NAME -> res.andWhere {
|
||||||
|
CategoryTable.name greater after.value
|
||||||
|
}
|
||||||
|
CategoryOrderBy.ORDER -> res.andWhere {
|
||||||
|
CategoryTable.order greater after.value.toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (before != null) {
|
||||||
|
when (orderBy) {
|
||||||
|
CategoryOrderBy.ID, null -> res.andWhere {
|
||||||
|
CategoryTable.id less before.value.toInt()
|
||||||
|
}
|
||||||
|
CategoryOrderBy.NAME -> res.andWhere {
|
||||||
|
CategoryTable.name less before.value
|
||||||
|
}
|
||||||
|
CategoryOrderBy.ORDER -> res.andWhere {
|
||||||
|
CategoryTable.order less before.value.toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first != null) {
|
||||||
|
res.limit(first, offset?.toLong() ?: 0)
|
||||||
|
} else if (last != null) {
|
||||||
|
res.limit(last)
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryResults(total, firstResult, lastResult, res.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
return results.map { CategoryType(it) }.toNodeList()
|
val resultsAsType = queryResults.results.map { CategoryType(it) }
|
||||||
|
|
||||||
|
return CategoryNodeList(
|
||||||
|
resultsAsType,
|
||||||
|
CategoryNodeList.CategoryEdges(
|
||||||
|
cursor = getAsCursor(orderBy, resultsAsType.last()),
|
||||||
|
node = resultsAsType.last()
|
||||||
|
),
|
||||||
|
pageInfo = PageInfo(
|
||||||
|
hasNextPage = queryResults.lastKey != resultsAsType.last().id,
|
||||||
|
hasPreviousPage = queryResults.firstKey != resultsAsType.first().id,
|
||||||
|
startCursor = getAsCursor(orderBy, resultsAsType.first()),
|
||||||
|
endCursor = getAsCursor(orderBy, resultsAsType.last())
|
||||||
|
),
|
||||||
|
totalCount = queryResults.total.toInt()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,12 +63,12 @@ class MangaQuery {
|
|||||||
LAST_FETCHED_AT
|
LAST_FETCHED_AT
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAsCursor(orderBy: MangaOrderBy?, manga: MangaType): Cursor {
|
private fun getAsCursor(orderBy: MangaOrderBy?, type: MangaType): Cursor {
|
||||||
val value = when (orderBy) {
|
val value = when (orderBy) {
|
||||||
MangaOrderBy.ID, null -> manga.id.toString()
|
MangaOrderBy.ID, null -> type.id.toString()
|
||||||
MangaOrderBy.TITLE -> manga.title
|
MangaOrderBy.TITLE -> type.title
|
||||||
MangaOrderBy.IN_LIBRARY_AT -> manga.inLibraryAt.toString()
|
MangaOrderBy.IN_LIBRARY_AT -> type.inLibraryAt.toString()
|
||||||
MangaOrderBy.LAST_FETCHED_AT -> manga.lastFetchedAt.toString()
|
MangaOrderBy.LAST_FETCHED_AT -> type.lastFetchedAt.toString()
|
||||||
}
|
}
|
||||||
return Cursor(value)
|
return Cursor(value)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user