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:
@@ -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)
|
||||
}
|
||||
|
||||
+40
@@ -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()
|
||||
}
|
||||
+16
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user