Add default category to the database (#561)

* Add default category to the database

* Fix getCategorySize
This commit is contained in:
Mitchell Syer
2023-05-26 19:50:21 -04:00
committed by GitHub
parent a81d01d2e3
commit 1e82c879bf
5 changed files with 72 additions and 19 deletions

View File

@@ -12,6 +12,7 @@ import org.dataloader.DataLoader
import org.dataloader.DataLoaderFactory import org.dataloader.DataLoaderFactory
import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger
import org.jetbrains.exposed.sql.addLogger import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.andWhere
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.MangaNodeList import suwayomi.tachidesk.graphql.types.MangaNodeList
@@ -42,10 +43,23 @@ class MangaForCategoryDataLoader : KotlinDataLoader<Int, MangaNodeList> {
future { future {
transaction { transaction {
addLogger(Slf4jSqlDebugLogger) addLogger(Slf4jSqlDebugLogger)
val itemsByRef = CategoryMangaTable.innerJoin(MangaTable).select { CategoryMangaTable.category inList ids } val itemsByRef = if (ids.contains(0)) {
MangaTable
.leftJoin(CategoryMangaTable)
.select { MangaTable.inLibrary eq true }
.andWhere { CategoryMangaTable.manga.isNull() }
.map { MangaType(it) }
.let {
mapOf(0 to it)
}
} else {
emptyMap()
} + CategoryMangaTable.innerJoin(MangaTable)
.select { CategoryMangaTable.category inList ids }
.map { Pair(it[CategoryMangaTable.category].value, MangaType(it)) } .map { Pair(it[CategoryMangaTable.category].value, MangaType(it)) }
.groupBy { it.first } .groupBy { it.first }
.mapValues { it.value.map { pair -> pair.second } } .mapValues { it.value.map { pair -> pair.second } }
ids.map { (itemsByRef[it] ?: emptyList()).toNodeList() } ids.map { (itemsByRef[it] ?: emptyList()).toNodeList() }
} }
} }

View File

@@ -10,6 +10,7 @@ package suwayomi.tachidesk.manga.impl
import org.jetbrains.exposed.sql.SortOrder import org.jetbrains.exposed.sql.SortOrder
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.andWhere
import org.jetbrains.exposed.sql.deleteWhere import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.insertAndGetId import org.jetbrains.exposed.sql.insertAndGetId
@@ -19,7 +20,6 @@ import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update import org.jetbrains.exposed.sql.update
import suwayomi.tachidesk.manga.impl.CategoryManga.removeMangaFromCategory import suwayomi.tachidesk.manga.impl.CategoryManga.removeMangaFromCategory
import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass
import suwayomi.tachidesk.manga.model.dataclass.IncludeInUpdate
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.CategoryMetaTable import suwayomi.tachidesk.manga.model.table.CategoryMetaTable
import suwayomi.tachidesk.manga.model.table.CategoryTable import suwayomi.tachidesk.manga.model.table.CategoryTable
@@ -54,7 +54,7 @@ object Category {
transaction { transaction {
CategoryTable.update({ CategoryTable.id eq categoryId }) { CategoryTable.update({ CategoryTable.id eq categoryId }) {
if (name != null && !name.equals(DEFAULT_CATEGORY_NAME, ignoreCase = true)) it[CategoryTable.name] = name if (name != null && !name.equals(DEFAULT_CATEGORY_NAME, ignoreCase = true)) it[CategoryTable.name] = name
if (isDefault != null) it[CategoryTable.isDefault] = isDefault if (isDefault != null && categoryId != DEFAULT_CATEGORY_ID) it[CategoryTable.isDefault] = isDefault
if (includeInUpdate != null) it[CategoryTable.includeInUpdate] = includeInUpdate if (includeInUpdate != null) it[CategoryTable.includeInUpdate] = includeInUpdate
} }
} }
@@ -64,6 +64,7 @@ object Category {
* Move the category from order number `from` to `to` * Move the category from order number `from` to `to`
*/ */
fun reorderCategory(from: Int, to: Int) { fun reorderCategory(from: Int, to: Int) {
if (from == 0 || to == 0) return
transaction { transaction {
val categories = CategoryTable.selectAll().orderBy(CategoryTable.order to SortOrder.ASC).toMutableList() val categories = CategoryTable.selectAll().orderBy(CategoryTable.order to SortOrder.ASC).toMutableList()
categories.add(to - 1, categories.removeAt(from - 1)) categories.add(to - 1, categories.removeAt(from - 1))
@@ -76,6 +77,7 @@ object Category {
} }
fun removeCategory(categoryId: Int) { fun removeCategory(categoryId: Int) {
if (categoryId == DEFAULT_CATEGORY_ID) return
transaction { transaction {
CategoryMangaTable.select { CategoryMangaTable.category eq categoryId }.forEach { CategoryMangaTable.select { CategoryMangaTable.category eq categoryId }.forEach {
removeMangaFromCategory(it[CategoryMangaTable.manga].value, categoryId) removeMangaFromCategory(it[CategoryMangaTable.manga].value, categoryId)
@@ -97,24 +99,32 @@ object Category {
} }
} }
private fun needsDefaultCategory() = transaction {
MangaTable
.leftJoin(CategoryMangaTable)
.select { MangaTable.inLibrary eq true }
.andWhere { CategoryMangaTable.manga.isNull() }
.empty()
.not()
}
const val DEFAULT_CATEGORY_ID = 0 const val DEFAULT_CATEGORY_ID = 0
const val DEFAULT_CATEGORY_NAME = "Default" const val DEFAULT_CATEGORY_NAME = "Default"
private fun addDefaultIfNecessary(categories: List<CategoryDataClass>): List<CategoryDataClass> {
val defaultCategorySize = MangaTable.select { (MangaTable.inLibrary eq true) and (MangaTable.defaultCategory eq true) }.count().toInt()
return if (defaultCategorySize > 0) {
listOf(CategoryDataClass(DEFAULT_CATEGORY_ID, 0, DEFAULT_CATEGORY_NAME, true, defaultCategorySize, IncludeInUpdate.UNSET)) + categories
} else {
categories
}
}
fun getCategoryList(): List<CategoryDataClass> { fun getCategoryList(): List<CategoryDataClass> {
return transaction { return transaction {
val categories = CategoryTable.selectAll().orderBy(CategoryTable.order to SortOrder.ASC).map { CategoryTable.selectAll()
CategoryTable.toDataClass(it) .orderBy(CategoryTable.order to SortOrder.ASC)
} .let {
if (needsDefaultCategory()) {
addDefaultIfNecessary(categories) it
} else {
it.andWhere { CategoryTable.id neq DEFAULT_CATEGORY_ID }
}
}
.map {
CategoryTable.toDataClass(it)
}
} }
} }
@@ -128,8 +138,15 @@ object Category {
fun getCategorySize(categoryId: Int): Int { fun getCategorySize(categoryId: Int): Int {
return transaction { return transaction {
CategoryMangaTable.select { if (categoryId == DEFAULT_CATEGORY_ID) {
CategoryMangaTable.category eq categoryId MangaTable
.leftJoin(CategoryMangaTable)
.select { MangaTable.inLibrary eq true }
.andWhere { CategoryMangaTable.manga.isNull() }
} else {
CategoryMangaTable.select {
CategoryMangaTable.category eq categoryId
}
}.count().toInt() }.count().toInt()
} }
} }

View File

@@ -33,6 +33,7 @@ import suwayomi.tachidesk.manga.model.table.toDataClass
object CategoryManga { object CategoryManga {
fun addMangaToCategory(mangaId: Int, categoryId: Int) { fun addMangaToCategory(mangaId: Int, categoryId: Int) {
if (categoryId == DEFAULT_CATEGORY_ID) return
fun notAlreadyInCategory() = CategoryMangaTable.select { (CategoryMangaTable.category eq categoryId) and (CategoryMangaTable.manga eq mangaId) }.isEmpty() fun notAlreadyInCategory() = CategoryMangaTable.select { (CategoryMangaTable.category eq categoryId) and (CategoryMangaTable.manga eq mangaId) }.isEmpty()
transaction { transaction {
@@ -50,6 +51,7 @@ object CategoryManga {
} }
fun removeMangaFromCategory(mangaId: Int, categoryId: Int) { fun removeMangaFromCategory(mangaId: Int, categoryId: Int) {
if (categoryId == DEFAULT_CATEGORY_ID) return
transaction { transaction {
CategoryMangaTable.deleteWhere { (CategoryMangaTable.category eq categoryId) and (CategoryMangaTable.manga eq mangaId) } CategoryMangaTable.deleteWhere { (CategoryMangaTable.category eq categoryId) and (CategoryMangaTable.manga eq mangaId) }
if (CategoryMangaTable.select { CategoryMangaTable.manga eq mangaId }.count() == 0L) { if (CategoryMangaTable.select { CategoryMangaTable.manga eq mangaId }.count() == 0L) {

View File

@@ -7,6 +7,7 @@ package suwayomi.tachidesk.manga.impl
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
@@ -22,7 +23,9 @@ object Library {
val manga = getManga(mangaId) val manga = getManga(mangaId)
if (!manga.inLibrary) { if (!manga.inLibrary) {
transaction { transaction {
val defaultCategories = CategoryTable.select { CategoryTable.isDefault eq true }.toList() val defaultCategories = CategoryTable.select {
(CategoryTable.isDefault eq true) and (CategoryTable.id neq Category.DEFAULT_CATEGORY_ID)
}.toList()
val existingCategories = CategoryMangaTable.select { CategoryMangaTable.manga eq mangaId }.toList() val existingCategories = CategoryMangaTable.select { CategoryMangaTable.manga eq mangaId }.toList()
MangaTable.update({ MangaTable.id eq manga.id }) { MangaTable.update({ MangaTable.id eq manga.id }) {

View File

@@ -0,0 +1,17 @@
package suwayomi.tachidesk.server.database.migration
import de.neonew.exposed.migrations.helpers.SQLMigration
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
@Suppress("ClassName", "unused")
class M0027_AddDefaultCategory : SQLMigration() {
override val sql: String = """
INSERT INTO CATEGORY (ID, NAME, IS_DEFAULT, "ORDER", INCLUDE_IN_UPDATE) VALUES (0, 'Default', TRUE, 0, -1)
""".trimIndent()
}