From 607919f40f7ed008299ca71792f7171edbb9c895 Mon Sep 17 00:00:00 2001 From: Syer10 Date: Sun, 2 Apr 2023 17:33:19 -0400 Subject: [PATCH] Implement more query parameters --- .../graphql/queries/CategoryQuery.kt | 41 +++++++++++++++-- .../tachidesk/graphql/queries/ChapterQuery.kt | 46 ++++++++++++++++--- .../tachidesk/graphql/queries/MangaQuery.kt | 37 ++++++++++++++- .../tachidesk/graphql/queries/UpdatesQuery.kt | 2 - .../graphql/queries/util/GreaterOrLessThan.kt | 42 +++++++++++++++++ 5 files changed, 153 insertions(+), 15 deletions(-) create mode 100644 server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/util/GreaterOrLessThan.kt diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/CategoryQuery.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/CategoryQuery.kt index ca646742..e2cd19ab 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/CategoryQuery.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/CategoryQuery.kt @@ -9,6 +9,8 @@ package suwayomi.tachidesk.graphql.queries import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment +import org.jetbrains.exposed.sql.SortOrder +import org.jetbrains.exposed.sql.andWhere import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction import suwayomi.tachidesk.graphql.types.CategoryType @@ -17,9 +19,6 @@ import java.util.concurrent.CompletableFuture /** * TODO Queries - * - Sort? - * - Query by name - * - In ID list * - Paged queries * * TODO Mutations @@ -36,9 +35,41 @@ class CategoryQuery { return dataFetchingEnvironment.getValueFromDataLoader("CategoryDataLoader", id) } - fun categories(): List { + enum class CategorySort { + ID, + NAME, + ORDER + } + + data class CategoriesQueryInput( + val sort: CategorySort? = null, + val sortOrder: SortOrder? = null, + val ids: List? = null, + val query: String? = null + ) + + fun categories(input: CategoriesQueryInput? = null): List { val results = transaction { - CategoryTable.selectAll().toList() + val res = CategoryTable.selectAll() + + if (input != null) { + if (input.ids != null) { + res.andWhere { CategoryTable.id inList input.ids } + } + if (!input.query.isNullOrEmpty()) { + res.andWhere { CategoryTable.name like input.query } + } + val orderBy = when (input.sort) { + 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() } return results.map { CategoryType(it) } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ChapterQuery.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ChapterQuery.kt index e901c2cc..372cde67 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ChapterQuery.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ChapterQuery.kt @@ -9,6 +9,7 @@ package suwayomi.tachidesk.graphql.queries import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment +import org.jetbrains.exposed.sql.SortOrder import org.jetbrains.exposed.sql.andWhere import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction @@ -18,11 +19,7 @@ import java.util.concurrent.CompletableFuture /** * TODO Queries - * - Filter by read - * - Filter by bookmarked - * - Filter by downloaded * - Filter by scanlators - * - Sort? Upload date, source order, last read, chapter number * - Get page list? * * TODO Mutations @@ -38,9 +35,23 @@ class ChapterQuery { return dataFetchingEnvironment.getValueFromDataLoader("ChapterDataLoader", id) } + enum class ChapterSort { + SOURCE_ORDER, + NAME, + UPLOAD_DATE, + CHAPTER_NUMBER, + LAST_READ_AT, + FETCHED_AT + } + data class ChapterQueryInput( val ids: List? = null, val mangaIds: List? = null, + val read: Boolean? = null, + val bookmarked: Boolean? = null, + val downloaded: Boolean? = null, + val sort: ChapterSort? = null, + val sortOrder: SortOrder? = null, val page: Int? = null, val count: Int? = null ) @@ -51,15 +62,36 @@ class ChapterQuery { if (input != null) { if (input.mangaIds != null) { - res = res.andWhere { ChapterTable.manga inList input.mangaIds } + res.andWhere { ChapterTable.manga inList input.mangaIds } } if (input.ids != null) { - res = res.andWhere { ChapterTable.id inList input.ids } + res.andWhere { ChapterTable.id inList input.ids } } + if (input.read != null) { + res.andWhere { ChapterTable.isRead eq input.read } + } + if (input.bookmarked != null) { + res.andWhere { ChapterTable.isBookmarked eq input.bookmarked } + } + if (input.downloaded != null) { + res.andWhere { ChapterTable.isDownloaded eq input.downloaded } + } + val orderBy = when (input.sort) { + ChapterSort.SOURCE_ORDER, null -> ChapterTable.sourceOrder + ChapterSort.NAME -> ChapterTable.name + ChapterSort.UPLOAD_DATE -> ChapterTable.date_upload + ChapterSort.CHAPTER_NUMBER -> ChapterTable.chapter_number + ChapterSort.LAST_READ_AT -> ChapterTable.lastReadAt + ChapterSort.FETCHED_AT -> ChapterTable.fetchedAt + } + res.orderBy(orderBy, order = input.sortOrder ?: SortOrder.ASC) + if (input.count != null) { val offset = if (input.page == null) 0 else (input.page * input.count).toLong() - res = res.limit(input.count, offset) + res.limit(input.count, offset) } + } else { + res.orderBy(ChapterTable.sourceOrder) } res.toList() diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MangaQuery.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MangaQuery.kt index a6950dc0..028db3f8 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MangaQuery.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MangaQuery.kt @@ -9,10 +9,13 @@ package suwayomi.tachidesk.graphql.queries import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment +import org.jetbrains.exposed.sql.SortOrder import org.jetbrains.exposed.sql.andWhere import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction +import suwayomi.tachidesk.graphql.queries.util.GreaterOrLessThanLong +import suwayomi.tachidesk.graphql.queries.util.andWhereGreaterOrLessThen import suwayomi.tachidesk.graphql.types.MangaType import suwayomi.tachidesk.manga.model.table.CategoryMangaTable import suwayomi.tachidesk.manga.model.table.MangaTable @@ -21,7 +24,6 @@ import java.util.concurrent.CompletableFuture /** * TODO Queries * - Query options(optionally query the title, description, or/and) - * - Sort? * * TODO Mutations * - Favorite @@ -39,9 +41,21 @@ class MangaQuery { return dataFetchingEnvironment.getValueFromDataLoader("MangaDataLoader", id) } + enum class MangaSort { + ID, + TITLE, + IN_LIBRARY_AT, + LAST_FETCHED_AT + } + data class MangaQueryInput( val ids: List? = null, val categoryIds: List? = null, + val sourceIds: List? = null, + val inLibrary: Boolean? = null, + val inLibraryAt: GreaterOrLessThanLong? = null, + val sort: MangaSort? = null, + val sortOrder: SortOrder? = null, val page: Int? = null, val count: Int? = null ) @@ -58,6 +72,27 @@ class MangaQuery { if (input.ids != null) { res.andWhere { MangaTable.id inList input.ids } } + if (input.sourceIds != null) { + res.andWhere { MangaTable.sourceReference inList input.sourceIds } + } + if (input.inLibrary != null) { + res.andWhere { MangaTable.inLibrary eq input.inLibrary } + } + if (input.inLibraryAt != null) { + res.andWhereGreaterOrLessThen( + column = MangaTable.inLibraryAt, + greaterOrLessThan = input.inLibraryAt + ) + } + if (input.sort != null) { + val orderBy = when (input.sort) { + MangaSort.ID -> MangaTable.id + MangaSort.TITLE -> MangaTable.title + MangaSort.IN_LIBRARY_AT -> MangaTable.inLibraryAt + MangaSort.LAST_FETCHED_AT -> MangaTable.lastFetchedAt + } + res.orderBy(orderBy, order = input.sortOrder ?: SortOrder.ASC) + } if (input.count != null) { val offset = if (input.page == null) 0 else (input.page * input.count).toLong() res.limit(input.count, offset) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/UpdatesQuery.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/UpdatesQuery.kt index e5742e25..df4f50d3 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/UpdatesQuery.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/UpdatesQuery.kt @@ -8,8 +8,6 @@ package suwayomi.tachidesk.graphql.queries import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.transactions.transaction diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/util/GreaterOrLessThan.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/util/GreaterOrLessThan.kt new file mode 100644 index 00000000..7be592fa --- /dev/null +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/util/GreaterOrLessThan.kt @@ -0,0 +1,42 @@ +package suwayomi.tachidesk.graphql.queries.util + +import org.jetbrains.exposed.sql.Column +import org.jetbrains.exposed.sql.Query +import org.jetbrains.exposed.sql.andWhere + +interface GreaterOrLessThan> { + val value: T + val type: GreaterOrLessThanType +} + +data class GreaterOrLessThanLong( + override val value: Long, + override val type: GreaterOrLessThanType +) : GreaterOrLessThan + +enum class GreaterOrLessThanType { + GREATER_THAN, + GREATER_THAN_OR_EQ, + LESS_THAN, + LESS_THAN_OR_EQ +} + +fun > Query.andWhereGreaterOrLessThen( + column: Column, + greaterOrLessThan: GreaterOrLessThan +) { + when (greaterOrLessThan.type) { + GreaterOrLessThanType.GREATER_THAN -> andWhere { + column greater greaterOrLessThan.value // toValue() + } + GreaterOrLessThanType.GREATER_THAN_OR_EQ -> andWhere { + column greaterEq greaterOrLessThan.value // toValue() + } + GreaterOrLessThanType.LESS_THAN -> andWhere { + column less greaterOrLessThan.value // toValue() + } + GreaterOrLessThanType.LESS_THAN_OR_EQ -> andWhere { + column lessEq greaterOrLessThan.value // toValue() + } + } +}