Improve database column references and default category handling (#563)

* Improve default category handling and add cascade to references where possible

* Minor fix for default category

* Make the default category always first in the normalization
This commit is contained in:
Mitchell Syer
2023-05-27 20:41:27 -04:00
committed by GitHub
parent 241abc3956
commit 6a7efafd9f
13 changed files with 76 additions and 31 deletions
@@ -59,7 +59,7 @@ class CategoryMutation {
CategoryMetaTable.deleteWhere { (CategoryMetaTable.ref eq categoryId) and (CategoryMetaTable.key eq key) }
val category= transaction {
val category = transaction {
CategoryType(CategoryTable.select { CategoryTable.id eq categoryId }.first())
}
@@ -170,7 +170,7 @@ class ChapterMutation {
ChapterMetaTable.deleteWhere { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) }
val chapter= transaction {
val chapter = transaction {
ChapterType(ChapterTable.select { ChapterTable.id eq chapterId }.first())
}
@@ -53,8 +53,8 @@ object Category {
fun updateCategory(categoryId: Int, name: String?, isDefault: Boolean?, includeInUpdate: Int?) {
transaction {
CategoryTable.update({ CategoryTable.id eq categoryId }) {
if (name != null && !name.equals(DEFAULT_CATEGORY_NAME, ignoreCase = true)) it[CategoryTable.name] = name
if (isDefault != null && categoryId != DEFAULT_CATEGORY_ID) it[CategoryTable.isDefault] = isDefault
if (categoryId != DEFAULT_CATEGORY_ID && name != null && !name.equals(DEFAULT_CATEGORY_NAME, ignoreCase = true)) it[CategoryTable.name] = name
if (categoryId != DEFAULT_CATEGORY_ID && isDefault != null) it[CategoryTable.isDefault] = isDefault
if (includeInUpdate != null) it[CategoryTable.includeInUpdate] = includeInUpdate
}
}
@@ -79,9 +79,6 @@ object Category {
fun removeCategory(categoryId: Int) {
if (categoryId == DEFAULT_CATEGORY_ID) return
transaction {
CategoryMangaTable.select { CategoryMangaTable.category eq categoryId }.forEach {
removeMangaFromCategory(it[CategoryMangaTable.manga].value, categoryId)
}
CategoryTable.deleteWhere { CategoryTable.id eq categoryId }
normalizeCategories()
}
@@ -90,12 +87,14 @@ object Category {
/** make sure category order numbers starts from 1 and is consecutive */
private fun normalizeCategories() {
transaction {
val categories = CategoryTable.selectAll().orderBy(CategoryTable.order to SortOrder.ASC)
categories.forEachIndexed { index, cat ->
CategoryTable.update({ CategoryTable.id eq cat[CategoryTable.id].value }) {
it[CategoryTable.order] = index + 1
CategoryTable.selectAll()
.orderBy(CategoryTable.order to SortOrder.ASC)
.sortedWith(compareBy({ it[CategoryTable.id].value != 0 }, { it[CategoryTable.order] }))
.forEachIndexed { index, cat ->
CategoryTable.update({ CategoryTable.id eq cat[CategoryTable.id].value }) {
it[CategoryTable.order] = index
}
}
}
}
}
@@ -19,7 +19,6 @@ import org.jetbrains.exposed.sql.leftJoin
import org.jetbrains.exposed.sql.max
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import org.jetbrains.exposed.sql.wrapAsExpression
import suwayomi.tachidesk.manga.impl.Category.DEFAULT_CATEGORY_ID
import suwayomi.tachidesk.manga.impl.util.lang.isEmpty
@@ -42,10 +41,6 @@ object CategoryManga {
it[CategoryMangaTable.category] = categoryId
it[CategoryMangaTable.manga] = mangaId
}
MangaTable.update({ MangaTable.id eq mangaId }) {
it[MangaTable.defaultCategory] = false
}
}
}
}
@@ -54,11 +49,6 @@ object CategoryManga {
if (categoryId == DEFAULT_CATEGORY_ID) return
transaction {
CategoryMangaTable.deleteWhere { (CategoryMangaTable.category eq categoryId) and (CategoryMangaTable.manga eq mangaId) }
if (CategoryMangaTable.select { CategoryMangaTable.manga eq mangaId }.count() == 0L) {
MangaTable.update({ MangaTable.id eq mangaId }) {
it[MangaTable.defaultCategory] = true
}
}
}
}
@@ -93,8 +83,9 @@ object CategoryManga {
val query = if (categoryId == DEFAULT_CATEGORY_ID) {
MangaTable
.leftJoin(ChapterTable, { MangaTable.id }, { ChapterTable.manga })
.leftJoin(CategoryMangaTable)
.slice(columns = selectedColumns)
.select { (MangaTable.inLibrary eq true) and (MangaTable.defaultCategory eq true) }
.select { (MangaTable.inLibrary eq true) and CategoryMangaTable.category.isNull() }
} else {
MangaTable
.innerJoin(CategoryMangaTable)
@@ -31,7 +31,6 @@ object Library {
MangaTable.update({ MangaTable.id eq manga.id }) {
it[inLibrary] = true
it[inLibraryAt] = Instant.now().epochSecond
it[defaultCategory] = defaultCategories.isEmpty() && existingCategories.isEmpty()
}
if (existingCategories.isEmpty()) {
@@ -8,8 +8,9 @@ package suwayomi.tachidesk.manga.model.table
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ReferenceOption
object CategoryMangaTable : IntIdTable() {
val category = reference("category", CategoryTable)
val manga = reference("manga", MangaTable)
val category = reference("category", CategoryTable, ReferenceOption.CASCADE)
val manga = reference("manga", MangaTable, ReferenceOption.CASCADE)
}
@@ -8,6 +8,7 @@ package suwayomi.tachidesk.manga.model.table
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ReferenceOption
import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
@@ -37,7 +38,7 @@ object ChapterTable : IntIdTable() {
val pageCount = integer("page_count").default(-1)
val manga = reference("manga", MangaTable)
val manga = reference("manga", MangaTable, ReferenceOption.CASCADE)
}
fun ChapterTable.toDataClass(chapterEntry: ResultRow) =
@@ -32,7 +32,6 @@ object MangaTable : IntIdTable() {
val thumbnailUrlLastFetched = long("thumbnail_url_last_fetched").default(0)
val inLibrary = bool("in_library").default(false)
val defaultCategory = bool("default_category").default(true)
val inLibraryAt = long("in_library_at").default(0)
// the [source] field name is used by some ancestor of IntIdTable
@@ -8,11 +8,12 @@ package suwayomi.tachidesk.manga.model.table
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ReferenceOption
object PageTable : IntIdTable() {
val index = integer("index")
val url = varchar("url", 2048)
val imageUrl = varchar("imageUrl", 2048).nullable()
val chapter = reference("chapter", ChapterTable)
val chapter = reference("chapter", ChapterTable, ReferenceOption.CASCADE)
}
@@ -0,0 +1,40 @@
package suwayomi.tachidesk.server.database.migration
import de.neonew.exposed.migrations.helpers.SQLMigration
@Suppress("ClassName", "unused")
class M0028_AddCascade : SQLMigration() {
override val sql: String = """
alter table CATEGORYMANGA
drop constraint FK_CATEGORYMANGA_CATEGORY_ID;
alter table CATEGORYMANGA
add constraint FK_CATEGORYMANGA_CATEGORY_ID
foreign key (CATEGORY) references CATEGORY
on delete cascade;
alter table CATEGORYMANGA
drop constraint FK_CATEGORYMANGA_MANGA_ID;
alter table CATEGORYMANGA
add constraint FK_CATEGORYMANGA_MANGA_ID
foreign key (MANGA) references MANGA
on delete cascade;
alter table CHAPTER
drop constraint FK_CHAPTER_MANGA_ID;
alter table CHAPTER
add constraint FK_CHAPTER_MANGA_ID
foreign key (MANGA) references MANGA
on delete cascade;
alter table PAGE
drop constraint FK_PAGE_CHAPTER_ID;
alter table PAGE
add constraint FK_PAGE_CHAPTER_ID
foreign key (CHAPTER) references CHAPTER
on delete cascade;
""".trimIndent()
}
@@ -0,0 +1,16 @@
package suwayomi.tachidesk.server.database.migration
/*
* 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/. */
import de.neonew.exposed.migrations.helpers.DropColumnMigration
@Suppress("ClassName", "unused")
class M0029_DropMangaDefaultCategory : DropColumnMigration(
"Manga",
"default_category"
)
@@ -71,7 +71,6 @@ internal class UpdateControllerTest : ApplicationTest() {
it[title] = _title
it[url] = _title
it[sourceReference] = 1
it[defaultCategory] = true
it[inLibrary] = true
}.value
}
@@ -38,7 +38,6 @@ fun createLibraryManga(
it[title] = _title
it[url] = _title
it[sourceReference] = 1
it[defaultCategory] = true
it[inLibrary] = true
}.value
}