Start working on graphql paging

This commit is contained in:
Syer10
2023-04-02 20:15:09 -04:00
parent 607919f40f
commit 52bda2c080
21 changed files with 369 additions and 60 deletions
@@ -14,6 +14,8 @@ import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger
import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.CategoryNodeList
import suwayomi.tachidesk.graphql.types.CategoryNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.CategoryType
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.CategoryTable
@@ -32,9 +34,9 @@ class CategoryDataLoader : KotlinDataLoader<Int, CategoryType> {
}
}
class CategoriesForMangaDataLoader : KotlinDataLoader<Int, List<CategoryType>> {
class CategoriesForMangaDataLoader : KotlinDataLoader<Int, CategoryNodeList> {
override val dataLoaderName = "CategoriesForMangaDataLoader"
override fun getDataLoader(): DataLoader<Int, List<CategoryType>> = DataLoaderFactory.newDataLoader<Int, List<CategoryType>> { ids ->
override fun getDataLoader(): DataLoader<Int, CategoryNodeList> = DataLoaderFactory.newDataLoader<Int, CategoryNodeList> { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
@@ -43,7 +45,7 @@ class CategoriesForMangaDataLoader : KotlinDataLoader<Int, List<CategoryType>> {
.map { Pair(it[CategoryMangaTable.manga].value, CategoryType(it)) }
.groupBy { it.first }
.mapValues { it.value.map { pair -> pair.second } }
ids.map { itemsByRef[it] ?: emptyList() }
ids.map { (itemsByRef[it] ?: emptyList()).toNodeList() }
}
}
}
@@ -14,6 +14,8 @@ import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger
import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.ChapterNodeList
import suwayomi.tachidesk.graphql.types.ChapterNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.ChapterType
import suwayomi.tachidesk.manga.model.table.ChapterTable
import suwayomi.tachidesk.server.JavalinSetup.future
@@ -31,16 +33,16 @@ class ChapterDataLoader : KotlinDataLoader<Int, ChapterType> {
}
}
class ChaptersForMangaDataLoader : KotlinDataLoader<Int, List<ChapterType>> {
class ChaptersForMangaDataLoader : KotlinDataLoader<Int, ChapterNodeList> {
override val dataLoaderName = "ChaptersForMangaDataLoader"
override fun getDataLoader(): DataLoader<Int, List<ChapterType>> = DataLoaderFactory.newDataLoader<Int, List<ChapterType>> { ids ->
override fun getDataLoader(): DataLoader<Int, ChapterNodeList> = DataLoaderFactory.newDataLoader<Int, ChapterNodeList> { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
val chaptersByMangaId = ChapterTable.select { ChapterTable.manga inList ids }
.map { ChapterType(it) }
.groupBy { it.mangaId }
ids.map { chaptersByMangaId[it] ?: emptyList() }
ids.map { (chaptersByMangaId[it] ?: emptyList()).toNodeList() }
}
}
}
@@ -14,6 +14,8 @@ import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger
import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.MangaNodeList
import suwayomi.tachidesk.graphql.types.MangaNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.MangaType
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.MangaTable
@@ -32,9 +34,9 @@ class MangaDataLoader : KotlinDataLoader<Int, MangaType> {
}
}
class MangaForCategoryDataLoader : KotlinDataLoader<Int, List<MangaType>> {
class MangaForCategoryDataLoader : KotlinDataLoader<Int, MangaNodeList> {
override val dataLoaderName = "MangaForCategoryDataLoader"
override fun getDataLoader(): DataLoader<Int, List<MangaType>> = DataLoaderFactory.newDataLoader<Int, List<MangaType>> { ids ->
override fun getDataLoader(): DataLoader<Int, MangaNodeList> = DataLoaderFactory.newDataLoader<Int, MangaNodeList> { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
@@ -42,7 +44,7 @@ class MangaForCategoryDataLoader : KotlinDataLoader<Int, List<MangaType>> {
.map { Pair(it[CategoryMangaTable.category].value, MangaType(it)) }
.groupBy { it.first }
.mapValues { it.value.map { pair -> pair.second } }
ids.map { itemsByRef[it] ?: emptyList() }
ids.map { (itemsByRef[it] ?: emptyList()).toNodeList() }
}
}
}
@@ -13,7 +13,8 @@ import suwayomi.tachidesk.graphql.types.ChapterMetaItem
import suwayomi.tachidesk.graphql.types.GlobalMetaItem
import suwayomi.tachidesk.graphql.types.MangaMetaItem
import suwayomi.tachidesk.graphql.types.MetaItem
import suwayomi.tachidesk.graphql.types.MetaType
import suwayomi.tachidesk.graphql.types.MetaNodeList
import suwayomi.tachidesk.graphql.types.MetaNodeList.Companion.toNodeList
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
import suwayomi.tachidesk.manga.model.table.MangaMetaTable
import suwayomi.tachidesk.server.JavalinSetup.future
@@ -33,46 +34,46 @@ class GlobalMetaDataLoader : KotlinDataLoader<String, MetaItem?> {
}
}
class ChapterMetaDataLoader : KotlinDataLoader<Int, MetaType> {
class ChapterMetaDataLoader : KotlinDataLoader<Int, MetaNodeList> {
override val dataLoaderName = "ChapterMetaDataLoader"
override fun getDataLoader(): DataLoader<Int, MetaType> = DataLoaderFactory.newDataLoader<Int, MetaType> { ids ->
override fun getDataLoader(): DataLoader<Int, MetaNodeList> = DataLoaderFactory.newDataLoader<Int, MetaNodeList> { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId = ChapterMetaTable.select { ChapterMetaTable.ref inList ids }
.map { ChapterMetaItem(it) }
.groupBy { it.ref }
ids.map { metasByRefId[it] ?: emptyList() }
ids.map { (metasByRefId[it] ?: emptyList()).toNodeList() }
}
}
}
}
class MangaMetaDataLoader : KotlinDataLoader<Int, MetaType> {
class MangaMetaDataLoader : KotlinDataLoader<Int, MetaNodeList> {
override val dataLoaderName = "MangaMetaDataLoader"
override fun getDataLoader(): DataLoader<Int, MetaType> = DataLoaderFactory.newDataLoader<Int, MetaType> { ids ->
override fun getDataLoader(): DataLoader<Int, MetaNodeList> = DataLoaderFactory.newDataLoader<Int, MetaNodeList> { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId = MangaMetaTable.select { MangaMetaTable.ref inList ids }
.map { MangaMetaItem(it) }
.groupBy { it.ref }
ids.map { metasByRefId[it] ?: emptyList() }
ids.map { (metasByRefId[it] ?: emptyList()).toNodeList() }
}
}
}
}
class CategoryMetaDataLoader : KotlinDataLoader<Int, MetaType> {
class CategoryMetaDataLoader : KotlinDataLoader<Int, MetaNodeList> {
override val dataLoaderName = "CategoryMetaDataLoader"
override fun getDataLoader(): DataLoader<Int, MetaType> = DataLoaderFactory.newDataLoader<Int, MetaType> { ids ->
override fun getDataLoader(): DataLoader<Int, MetaNodeList> = DataLoaderFactory.newDataLoader<Int, MetaNodeList> { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId = MangaMetaTable.select { MangaMetaTable.ref inList ids }
.map { CategoryMetaItem(it) }
.groupBy { it.ref }
ids.map { metasByRefId[it] ?: emptyList() }
ids.map { (metasByRefId[it] ?: emptyList()).toNodeList() }
}
}
}
@@ -14,6 +14,8 @@ import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger
import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.SourceNodeList
import suwayomi.tachidesk.graphql.types.SourceNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.SourceType
import suwayomi.tachidesk.manga.model.table.ExtensionTable
import suwayomi.tachidesk.manga.model.table.MangaTable
@@ -63,9 +65,9 @@ class SourceForMangaDataLoader : KotlinDataLoader<Int, SourceType?> {
}
}
class SourcesForExtensionDataLoader : KotlinDataLoader<String, List<SourceType>> {
class SourcesForExtensionDataLoader : KotlinDataLoader<String, SourceNodeList> {
override val dataLoaderName = "SourcesForExtensionDataLoader"
override fun getDataLoader(): DataLoader<String, List<SourceType>> = DataLoaderFactory.newDataLoader { ids ->
override fun getDataLoader(): DataLoader<String, SourceNodeList> = DataLoaderFactory.newDataLoader { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
@@ -76,7 +78,7 @@ class SourcesForExtensionDataLoader : KotlinDataLoader<String, List<SourceType>>
.groupBy { it.first }
.mapValues { it.value.mapNotNull { pair -> pair.second } }
ids.map { sourcesByExtensionPkg[it] ?: emptyList() }
ids.map { (sourcesByExtensionPkg[it] ?: emptyList()).toNodeList() }
}
}
}
@@ -13,6 +13,8 @@ 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.CategoryNodeList
import suwayomi.tachidesk.graphql.types.CategoryNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.CategoryType
import suwayomi.tachidesk.manga.model.table.CategoryTable
import java.util.concurrent.CompletableFuture
@@ -48,7 +50,7 @@ class CategoryQuery {
val query: String? = null
)
fun categories(input: CategoriesQueryInput? = null): List<CategoryType> {
fun categories(input: CategoriesQueryInput? = null): CategoryNodeList {
val results = transaction {
val res = CategoryTable.selectAll()
@@ -72,6 +74,6 @@ class CategoryQuery {
res.toList()
}
return results.map { CategoryType(it) }
return results.map { CategoryType(it) }.toNodeList()
}
}
@@ -13,6 +13,8 @@ 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.ChapterNodeList
import suwayomi.tachidesk.graphql.types.ChapterNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.ChapterType
import suwayomi.tachidesk.manga.model.table.ChapterTable
import java.util.concurrent.CompletableFuture
@@ -56,7 +58,7 @@ class ChapterQuery {
val count: Int? = null
)
fun chapters(input: ChapterQueryInput? = null): List<ChapterType> {
fun chapters(input: ChapterQueryInput? = null): ChapterNodeList {
val results = transaction {
var res = ChapterTable.selectAll()
@@ -97,6 +99,6 @@ class ChapterQuery {
res.toList()
}
return results.map { ChapterType(it) }
return results.map { ChapterType(it) }.toNodeList() // todo paged
}
}
@@ -11,6 +11,8 @@ import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.ExtensionNodeList
import suwayomi.tachidesk.graphql.types.ExtensionNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.ExtensionType
import suwayomi.tachidesk.manga.model.table.ExtensionTable
import java.util.concurrent.CompletableFuture
@@ -37,11 +39,11 @@ class ExtensionQuery {
return dataFetchingEnvironment.getValueFromDataLoader<String, ExtensionType>("ExtensionDataLoader", pkgName)
}
fun extensions(): List<ExtensionType> {
fun extensions(): ExtensionNodeList {
val results = transaction {
ExtensionTable.selectAll().toList()
}
return results.map { ExtensionType(it) }
return results.map { ExtensionType(it) }.toNodeList()
}
}
@@ -16,6 +16,8 @@ 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.MangaNodeList
import suwayomi.tachidesk.graphql.types.MangaNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.MangaType
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.MangaTable
@@ -60,7 +62,7 @@ class MangaQuery {
val count: Int? = null
)
fun mangas(input: MangaQueryInput? = null): List<MangaType> {
fun mangas(input: MangaQueryInput? = null): MangaNodeList {
val results = transaction {
var res = MangaTable.selectAll()
@@ -102,6 +104,6 @@ class MangaQuery {
res.toList()
}
return results.map { MangaType(it) }
return results.map { MangaType(it) }.toNodeList() // todo paged
}
}
@@ -14,6 +14,8 @@ import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.global.model.table.GlobalMetaTable
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
/**
@@ -30,11 +32,11 @@ class MetaQuery {
return dataFetchingEnvironment.getValueFromDataLoader<String, MetaItem?>("GlobalMetaDataLoader", key)
}
fun metas(): List<GlobalMetaItem> {
fun metas(): MetaNodeList {
val results = transaction {
GlobalMetaTable.selectAll().toList()
}
return results.map { GlobalMetaItem(it) }
return results.map { GlobalMetaItem(it) }.toNodeList()
}
}
@@ -11,6 +11,8 @@ import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.SourceNodeList
import suwayomi.tachidesk.graphql.types.SourceNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.SourceType
import suwayomi.tachidesk.manga.model.table.SourceTable
import java.util.concurrent.CompletableFuture
@@ -33,11 +35,11 @@ class SourceQuery {
return dataFetchingEnvironment.getValueFromDataLoader<Long, SourceType?>("SourceDataLoader", id)
}
fun sources(): List<SourceType> {
fun sources(): SourceNodeList {
val results = transaction {
SourceTable.selectAll().toList().mapNotNull { SourceType(it) }
}
return results
return results.toNodeList()
}
}
@@ -11,6 +11,8 @@ import org.jetbrains.exposed.sql.SortOrder
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.UpdatesNodeList
import suwayomi.tachidesk.graphql.types.UpdatesNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.UpdatesType
import suwayomi.tachidesk.manga.model.dataclass.PaginationFactor
import suwayomi.tachidesk.manga.model.table.ChapterTable
@@ -31,7 +33,7 @@ class UpdatesQuery {
val page: Int
)
fun updates(input: UpdatesQueryInput): List<UpdatesType> {
fun updates(input: UpdatesQueryInput): UpdatesNodeList {
val results = transaction {
ChapterTable.innerJoin(MangaTable)
.select { (MangaTable.inLibrary eq true) and (ChapterTable.fetchedAt greater MangaTable.inLibraryAt) }
@@ -42,6 +44,6 @@ class UpdatesQuery {
}
}
return results
return results.toNodeList() // todo paged
}
}
@@ -18,7 +18,7 @@ class CategoryType(
val order: Int,
val name: String,
val default: Boolean
) {
) : Node {
constructor(row: ResultRow) : this(
row[CategoryTable.id].value,
row[CategoryTable.order],
@@ -26,11 +26,42 @@ class CategoryType(
row[CategoryTable.isDefault]
)
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<MangaType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<MangaType>>("MangaForCategoryDataLoader", id)
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MangaNodeList>("MangaForCategoryDataLoader", id)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaType>("CategoryMetaDataLoader", id)
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaNodeList>("CategoryMetaDataLoader", id)
}
}
data class CategoryNodeList(
override val nodes: List<CategoryType>,
override val edges: CategoryEdges,
override val pageInfo: PageInfo,
override val totalCount: Int
) : NodeList() {
data class CategoryEdges(
override val cursor: Cursor,
override val node: CategoryType?
) : Edges()
companion object {
fun List<CategoryType>.toNodeList(): CategoryNodeList {
return CategoryNodeList(
nodes = this,
edges = CategoryEdges(
cursor = lastIndex,
node = lastOrNull()
),
pageInfo = PageInfo(
hasNextPage = false,
hasPreviousPage = false,
startCursor = 0,
endCursor = lastIndex
),
totalCount = size
)
}
}
}
@@ -31,7 +31,7 @@ class ChapterType(
val isDownloaded: Boolean,
val pageCount: Int
// val chapterCount: Int?,
) {
) : Node {
constructor(row: ResultRow) : this(
row[ChapterTable.id].value,
row[ChapterTable.url],
@@ -73,7 +73,38 @@ class ChapterType(
return dataFetchingEnvironment.getValueFromDataLoader<Int, MangaType>("MangaDataLoader", mangaId)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaType>("ChapterMetaDataLoader", id)
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaNodeList>("ChapterMetaDataLoader", id)
}
}
data class ChapterNodeList(
override val nodes: List<ChapterType>,
override val edges: ChapterEdges,
override val pageInfo: PageInfo,
override val totalCount: Int
) : NodeList() {
data class ChapterEdges(
override val cursor: Cursor,
override val node: ChapterType?
) : Edges()
companion object {
fun List<ChapterType>.toNodeList(): ChapterNodeList {
return ChapterNodeList(
nodes = this,
edges = ChapterEdges(
cursor = lastIndex,
node = lastOrNull()
),
pageInfo = PageInfo(
hasNextPage = false,
hasPreviousPage = false,
startCursor = 0,
endCursor = lastIndex
),
totalCount = size
)
}
}
}
@@ -24,7 +24,7 @@ class DownloadType(
var mangaDataClass: MangaDataClass,
@GraphQLIgnore
var chapterDataClass: ChapterDataClass
) {
) : Node {
constructor(downloadChapter: DownloadChapter) : this(
downloadChapter.chapter.id,
downloadChapter.chapterIndex,
@@ -44,3 +44,34 @@ class DownloadType(
return ChapterType(chapterDataClass)
}
}
data class DownloadNodeList(
override val nodes: List<DownloadType>,
override val edges: DownloadEdges,
override val pageInfo: PageInfo,
override val totalCount: Int
) : NodeList() {
data class DownloadEdges(
override val cursor: Cursor,
override val node: DownloadType?
) : Edges()
companion object {
fun List<DownloadType>.toNodeList(): DownloadNodeList {
return DownloadNodeList(
nodes = this,
edges = DownloadEdges(
cursor = lastIndex,
node = lastOrNull()
),
pageInfo = PageInfo(
hasNextPage = false,
hasPreviousPage = false,
startCursor = 0,
endCursor = lastIndex
),
totalCount = size
)
}
}
}
@@ -27,7 +27,7 @@ class ExtensionType(
val installed: Boolean,
val hasUpdate: Boolean,
val obsolete: Boolean
) {
) : Node {
constructor(row: ResultRow) : this(
apkName = row[ExtensionTable.apkName],
iconUrl = row[ExtensionTable.iconUrl],
@@ -42,7 +42,38 @@ class ExtensionType(
obsolete = row[ExtensionTable.isObsolete]
)
fun source(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<SourceType>> {
return dataFetchingEnvironment.getValueFromDataLoader<String, List<SourceType>>("SourcesForExtensionDataLoader", pkgName)
fun source(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<SourceNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<String, SourceNodeList>("SourcesForExtensionDataLoader", pkgName)
}
}
data class ExtensionNodeList(
override val nodes: List<ExtensionType>,
override val edges: ExtensionEdges,
override val pageInfo: PageInfo,
override val totalCount: Int
) : NodeList() {
data class ExtensionEdges(
override val cursor: Cursor,
override val node: ExtensionType?
) : Edges()
companion object {
fun List<ExtensionType>.toNodeList(): ExtensionNodeList {
return ExtensionNodeList(
nodes = this,
edges = ExtensionEdges(
cursor = lastIndex,
node = lastOrNull()
),
pageInfo = PageInfo(
hasNextPage = false,
hasPreviousPage = false,
startCursor = 0,
endCursor = lastIndex
),
totalCount = size
)
}
}
}
@@ -34,7 +34,7 @@ class MangaType(
val realUrl: String?,
var lastFetchedAt: Long?,
var chaptersLastFetchedAt: Long?
) {
) : Node {
constructor(row: ResultRow) : this(
row[MangaTable.id].value,
row[MangaTable.sourceReference],
@@ -88,15 +88,46 @@ class MangaType(
return Instant.now().epochSecond.minus(chaptersLastFetchedAt!!)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaType>("MangaMetaDataLoader", id)
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MetaNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MetaNodeList>("MangaMetaDataLoader", id)
}
fun categories(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<CategoryType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<CategoryType>>("CategoriesForMangaDataLoader", id)
fun categories(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<CategoryNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, CategoryNodeList>("CategoriesForMangaDataLoader", id)
}
fun source(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<SourceType?> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, SourceType?>("SourceForMangaDataLoader", id)
}
}
data class MangaNodeList(
override val nodes: List<MangaType>,
override val edges: MangaEdges,
override val pageInfo: PageInfo,
override val totalCount: Int
) : NodeList() {
data class MangaEdges(
override val cursor: Cursor,
override val node: MangaType?
) : Edges()
companion object {
fun List<MangaType>.toNodeList(): MangaNodeList {
return MangaNodeList(
nodes = this,
edges = MangaEdges(
cursor = lastIndex,
node = lastOrNull()
),
pageInfo = PageInfo(
hasNextPage = false,
hasPreviousPage = false,
startCursor = 0,
endCursor = lastIndex
),
totalCount = size
)
}
}
}
@@ -7,14 +7,12 @@ import suwayomi.tachidesk.manga.model.table.CategoryMetaTable
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
import suwayomi.tachidesk.manga.model.table.MangaMetaTable
typealias MetaType = List<MetaItem>
open class MetaItem(
val key: String,
val value: String,
@GraphQLIgnore
val ref: Int?
)
) : Node
class ChapterMetaItem(
private val row: ResultRow
@@ -31,3 +29,34 @@ class CategoryMetaItem(
class GlobalMetaItem(
private val row: ResultRow
) : MetaItem(row[GlobalMetaTable.key], row[GlobalMetaTable.value], null)
data class MetaNodeList(
override val nodes: List<MetaItem>,
override val edges: MetaEdges,
override val pageInfo: PageInfo,
override val totalCount: Int
) : NodeList() {
data class MetaEdges(
override val cursor: Cursor,
override val node: MetaItem?
) : Edges()
companion object {
fun List<MetaItem>.toNodeList(): MetaNodeList {
return MetaNodeList(
nodes = this,
edges = MetaEdges(
cursor = lastIndex,
node = lastOrNull()
),
pageInfo = PageInfo(
hasNextPage = false,
hasPreviousPage = false,
startCursor = 0,
endCursor = lastIndex
),
totalCount = size
)
}
}
}
@@ -0,0 +1,40 @@
package suwayomi.tachidesk.graphql.types
import com.expediagroup.graphql.generator.annotations.GraphQLDescription
interface Node
typealias Cursor = Int
abstract class NodeList {
@GraphQLDescription("A list of [T] objects.")
abstract val nodes: List<Node>
@GraphQLDescription("A list of edges which contains the [T] and cursor to aid in pagination.")
abstract val edges: Edges
@GraphQLDescription("Information to aid in pagination.")
abstract val pageInfo: PageInfo
@GraphQLDescription("The count of all nodes you could get from the connection.")
abstract val totalCount: Int
}
data class PageInfo(
@GraphQLDescription("When paginating forwards, are there more items?")
val hasNextPage: Boolean,
@GraphQLDescription("When paginating backwards, are there more items?")
val hasPreviousPage: Boolean,
@GraphQLDescription("When paginating backwards, the cursor to continue.")
val startCursor: Cursor,
@GraphQLDescription("When paginating forwards, the cursor to continue.")
val endCursor: Cursor
)
abstract class Edges {
@GraphQLDescription("A cursor for use in pagination.")
abstract val cursor: Cursor
@GraphQLDescription("The [T] at the end of the edge.")
abstract val node: Node?
}
@@ -29,7 +29,7 @@ class SourceType(
val isConfigurable: Boolean,
val isNsfw: Boolean,
val displayName: String
) {
) : Node {
constructor(source: SourceDataClass) : this(
id = source.id.toLong(),
name = source.name,
@@ -52,8 +52,8 @@ class SourceType(
displayName = catalogueSource.toString()
)
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<MangaType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Long, List<MangaType>>("MangaForSourceDataLoader", id)
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Long, MangaNodeList>("MangaForSourceDataLoader", id)
}
fun extension(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ExtensionType> {
@@ -75,3 +75,34 @@ fun SourceType(row: ResultRow): SourceType? {
return SourceType(row, sourceExtension, catalogueSource)
}
data class SourceNodeList(
override val nodes: List<SourceType>,
override val edges: SourceEdges,
override val pageInfo: PageInfo,
override val totalCount: Int
) : NodeList() {
data class SourceEdges(
override val cursor: Cursor,
override val node: SourceType?
) : Edges()
companion object {
fun List<SourceType>.toNodeList(): SourceNodeList {
return SourceNodeList(
nodes = this,
edges = SourceEdges(
cursor = lastIndex,
node = lastOrNull()
),
pageInfo = PageInfo(
hasNextPage = false,
hasPreviousPage = false,
startCursor = 0,
endCursor = lastIndex
),
totalCount = size
)
}
}
}
@@ -12,9 +12,40 @@ import org.jetbrains.exposed.sql.ResultRow
class UpdatesType(
val manga: MangaType,
val chapter: ChapterType
) {
) : Node {
constructor(row: ResultRow) : this(
manga = MangaType(row),
chapter = ChapterType(row)
)
}
data class UpdatesNodeList(
override val nodes: List<UpdatesType>,
override val edges: UpdatesEdges,
override val pageInfo: PageInfo,
override val totalCount: Int
) : NodeList() {
data class UpdatesEdges(
override val cursor: Cursor,
override val node: UpdatesType?
) : Edges()
companion object {
fun List<UpdatesType>.toNodeList(): UpdatesNodeList {
return UpdatesNodeList(
nodes = this,
edges = UpdatesEdges(
cursor = lastIndex,
node = lastOrNull()
),
pageInfo = PageInfo(
hasNextPage = false,
hasPreviousPage = false,
startCursor = 0,
endCursor = lastIndex
),
totalCount = size
)
}
}
}