mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-17 09:43:33 -05:00
Compare commits
3 Commits
renovate/m
...
e93efa9627
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e93efa9627 | ||
|
|
03a95e6652 | ||
|
|
c117d380a3 |
@@ -10,7 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||||||
- .
|
- .
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- .
|
- (Database/H2) Use the latest H2 database engine
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- (CloudFlareInterceptor) Don't send the `cf_clearance` cookie back to Flaresolverr
|
- (CloudFlareInterceptor) Don't send the `cf_clearance` cookie back to Flaresolverr
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
|
|||||||
* Metadata storage for clients, server/global level.
|
* Metadata storage for clients, server/global level.
|
||||||
*/
|
*/
|
||||||
object GlobalMetaTable : IntIdTable() {
|
object GlobalMetaTable : IntIdTable() {
|
||||||
val key = varchar("key", 256)
|
val key = varchar("meta_key", 256)
|
||||||
val value = varchar("value", 4096)
|
val value = varchar("value", 4096)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import suwayomi.tachidesk.manga.model.table.CategoryMetaTable.ref
|
|||||||
* Metadata storage for clients, about Category with id == [ref].
|
* Metadata storage for clients, about Category with id == [ref].
|
||||||
*/
|
*/
|
||||||
object CategoryMetaTable : IntIdTable() {
|
object CategoryMetaTable : IntIdTable() {
|
||||||
val key = varchar("key", 256)
|
val key = varchar("meta_key", 256)
|
||||||
val value = varchar("value", 4096)
|
val value = varchar("value", 4096)
|
||||||
val ref = reference("category_ref", CategoryTable, ReferenceOption.CASCADE)
|
val ref = reference("category_ref", CategoryTable, ReferenceOption.CASCADE)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import suwayomi.tachidesk.manga.model.table.ChapterMetaTable.ref
|
|||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
object ChapterMetaTable : IntIdTable() {
|
object ChapterMetaTable : IntIdTable() {
|
||||||
val key = varchar("key", 256)
|
val key = varchar("meta_key", 256)
|
||||||
val value = varchar("value", 4096)
|
val value = varchar("value", 4096)
|
||||||
val ref = reference("chapter_ref", ChapterTable, ReferenceOption.CASCADE)
|
val ref = reference("chapter_ref", ChapterTable, ReferenceOption.CASCADE)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import suwayomi.tachidesk.manga.model.table.MangaMetaTable.ref
|
|||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
object MangaMetaTable : IntIdTable() {
|
object MangaMetaTable : IntIdTable() {
|
||||||
val key = varchar("key", 256)
|
val key = varchar("meta_key", 256)
|
||||||
val value = varchar("value", 4096)
|
val value = varchar("value", 4096)
|
||||||
val ref = reference("manga_ref", MangaTable, ReferenceOption.CASCADE)
|
val ref = reference("manga_ref", MangaTable, ReferenceOption.CASCADE)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import suwayomi.tachidesk.manga.model.table.SourceMetaTable.ref
|
|||||||
* Metadata storage for clients, about Source with id == [ref].
|
* Metadata storage for clients, about Source with id == [ref].
|
||||||
*/
|
*/
|
||||||
object SourceMetaTable : IntIdTable() {
|
object SourceMetaTable : IntIdTable() {
|
||||||
val key = varchar("key", 256)
|
val key = varchar("meta_key", 256)
|
||||||
val value = varchar("value", 4096)
|
val value = varchar("value", 4096)
|
||||||
val ref = long("source_ref")
|
val ref = long("source_ref")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import suwayomi.tachidesk.server.util.ExitCode
|
|||||||
import suwayomi.tachidesk.server.util.shutdownApp
|
import suwayomi.tachidesk.server.util.shutdownApp
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.sql.SQLException
|
|
||||||
import kotlin.time.Duration.Companion.minutes
|
import kotlin.time.Duration.Companion.minutes
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
@@ -184,7 +183,7 @@ fun databaseUp() {
|
|||||||
}
|
}
|
||||||
val migrations = loadMigrationsFrom("suwayomi.tachidesk.server.database.migration", ServerConfig::class.java)
|
val migrations = loadMigrationsFrom("suwayomi.tachidesk.server.database.migration", ServerConfig::class.java)
|
||||||
runMigrations(migrations)
|
runMigrations(migrations)
|
||||||
} catch (e: SQLException) {
|
} catch (e: Exception) {
|
||||||
logger.error(e) { "Error up-to-database migration" }
|
logger.error(e) { "Error up-to-database migration" }
|
||||||
if (System.getProperty("crashOnFailedMigration").toBoolean()) {
|
if (System.getProperty("crashOnFailedMigration").toBoolean()) {
|
||||||
shutdownApp(ExitCode.DbMigrationFailure)
|
shutdownApp(ExitCode.DbMigrationFailure)
|
||||||
|
|||||||
@@ -9,9 +9,12 @@ import java.net.URLClassLoader
|
|||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
import kotlin.io.path.absolutePathString
|
import kotlin.io.path.absolutePathString
|
||||||
|
import kotlin.io.path.bufferedReader
|
||||||
|
import kotlin.io.path.bufferedWriter
|
||||||
import kotlin.io.path.copyTo
|
import kotlin.io.path.copyTo
|
||||||
import kotlin.io.path.createDirectories
|
import kotlin.io.path.createDirectories
|
||||||
import kotlin.io.path.deleteExisting
|
import kotlin.io.path.deleteExisting
|
||||||
|
import kotlin.io.path.deleteIfExists
|
||||||
import kotlin.io.path.div
|
import kotlin.io.path.div
|
||||||
import kotlin.io.path.exists
|
import kotlin.io.path.exists
|
||||||
import kotlin.io.path.name
|
import kotlin.io.path.name
|
||||||
@@ -46,6 +49,10 @@ object H2Migration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val script = Path("$dbBase.${h2Old.substringAfterLast('.')}.sql")
|
val script = Path("$dbBase.${h2Old.substringAfterLast('.')}.sql")
|
||||||
|
script.deleteIfExists()
|
||||||
|
|
||||||
|
val modifiedScript = Path("$dbBase.${h2Old.substringAfterLast('.')}.modified.sql")
|
||||||
|
modifiedScript.deleteIfExists()
|
||||||
|
|
||||||
// Backup original database.
|
// Backup original database.
|
||||||
val backup = Path("$dbBase.mv.db.${h2Old.substringAfterLast('.')}.backup")
|
val backup = Path("$dbBase.mv.db.${h2Old.substringAfterLast('.')}.backup")
|
||||||
@@ -72,19 +79,32 @@ object H2Migration {
|
|||||||
libsDir.resolve("h2-$h2New.bin"),
|
libsDir.resolve("h2-$h2New.bin"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Delete attempted migration if failed previously
|
||||||
|
val newDatabase = Path(rootDir, "database.${h2New.substringAfterLast('.')}.mv.db")
|
||||||
|
newDatabase.deleteIfExists()
|
||||||
|
|
||||||
|
val modifiedNewDatabase = Path(rootDir, "database.${h2Old.substringAfterLast('.')}.modified.${h2New.substringAfterLast('.')}.mv.db")
|
||||||
|
modifiedNewDatabase.deleteIfExists()
|
||||||
|
|
||||||
runMigrationTool(
|
runMigrationTool(
|
||||||
migrationJar = migrationJar,
|
migrationJar = migrationJar,
|
||||||
libsDir = libsDir,
|
libsDir = libsDir,
|
||||||
mvStore = mvStore,
|
mvStore = mvStore,
|
||||||
script = script,
|
script = script,
|
||||||
|
modifiedScript = modifiedScript,
|
||||||
h2Old = h2Old,
|
h2Old = h2Old,
|
||||||
h2New = h2New,
|
h2New = h2New,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Move database to proper path
|
// Move database to proper path
|
||||||
val newDatabase = Path(rootDir, "database.${h2New.substringAfterLast('.')}.mv.db")
|
if (modifiedNewDatabase.exists()) {
|
||||||
newDatabase.copyTo(mvStore, overwrite = true)
|
modifiedNewDatabase.copyTo(mvStore, overwrite = true)
|
||||||
newDatabase.deleteExisting()
|
modifiedNewDatabase.deleteExisting()
|
||||||
|
newDatabase.deleteIfExists()
|
||||||
|
} else {
|
||||||
|
newDatabase.copyTo(mvStore, overwrite = true)
|
||||||
|
newDatabase.deleteExisting()
|
||||||
|
}
|
||||||
|
|
||||||
logger.info { "H2 migration completed successfully." }
|
logger.info { "H2 migration completed successfully." }
|
||||||
}
|
}
|
||||||
@@ -123,6 +143,7 @@ object H2Migration {
|
|||||||
libsDir: Path,
|
libsDir: Path,
|
||||||
mvStore: Path,
|
mvStore: Path,
|
||||||
script: Path,
|
script: Path,
|
||||||
|
modifiedScript: Path,
|
||||||
h2Old: String,
|
h2Old: String,
|
||||||
h2New: String,
|
h2New: String,
|
||||||
) {
|
) {
|
||||||
@@ -136,32 +157,77 @@ object H2Migration {
|
|||||||
val main =
|
val main =
|
||||||
clazz.getMethod("main", Array<String>::class.java)
|
clazz.getMethod("main", Array<String>::class.java)
|
||||||
|
|
||||||
main.invoke(
|
try {
|
||||||
null,
|
main.invoke(
|
||||||
arrayOf(
|
null,
|
||||||
// h2 driver dir
|
arrayOf(
|
||||||
"-l",
|
// h2 driver dir
|
||||||
libsDir.absolutePathString(),
|
"-l",
|
||||||
// from version
|
libsDir.absolutePathString(),
|
||||||
"-f",
|
// from version
|
||||||
h2Old,
|
"-f",
|
||||||
// to version
|
h2Old,
|
||||||
"-t",
|
// to version
|
||||||
h2New,
|
"-t",
|
||||||
// user
|
h2New,
|
||||||
"-u",
|
// user
|
||||||
"",
|
"-u",
|
||||||
// password
|
"",
|
||||||
"-p",
|
// password
|
||||||
"",
|
"-p",
|
||||||
// database.mv.db
|
"",
|
||||||
"-d",
|
// database.mv.db
|
||||||
mvStore.absolutePathString(),
|
"-d",
|
||||||
// database backup in SQL
|
mvStore.absolutePathString(),
|
||||||
"-s",
|
// database backup in SQL
|
||||||
script.absolutePathString(),
|
"-s",
|
||||||
),
|
script.absolutePathString(),
|
||||||
)
|
),
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Modify raw .sql file as needed for compatibility
|
||||||
|
if (e.stackTraceToString().contains("Unknown data type: \"DATETIME\"; SQL statement:") && script.exists()) {
|
||||||
|
script.bufferedReader().use { reader ->
|
||||||
|
modifiedScript.bufferedWriter().use { writer ->
|
||||||
|
reader.forEachLine { line ->
|
||||||
|
writer.write(
|
||||||
|
line.replace(
|
||||||
|
" \"EXECUTED_AT\" DATETIME(9) NOT NULL",
|
||||||
|
" \"EXECUTED_AT\" TIMESTAMP(9) NOT NULL",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
writer.newLine()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main.invoke(
|
||||||
|
null,
|
||||||
|
arrayOf(
|
||||||
|
// h2 driver dir
|
||||||
|
"-l",
|
||||||
|
libsDir.absolutePathString(),
|
||||||
|
// from version
|
||||||
|
"-f",
|
||||||
|
h2Old,
|
||||||
|
// to version
|
||||||
|
"-t",
|
||||||
|
h2New,
|
||||||
|
// user
|
||||||
|
"-u",
|
||||||
|
"",
|
||||||
|
// password
|
||||||
|
"-p",
|
||||||
|
"",
|
||||||
|
// database.mv.db
|
||||||
|
"-d",
|
||||||
|
modifiedScript.absolutePathString(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,17 +10,10 @@ package suwayomi.tachidesk.server.database.migration
|
|||||||
* 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 de.neonew.exposed.migrations.helpers.SQLMigration
|
import de.neonew.exposed.migrations.helpers.SQLMigration
|
||||||
import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager
|
import suwayomi.tachidesk.server.database.migration.helpers.toSqlName
|
||||||
|
|
||||||
@Suppress("ClassName", "unused")
|
@Suppress("ClassName", "unused")
|
||||||
class M0023_CategoryMetaRefFix : SQLMigration() {
|
class M0023_CategoryMetaRefFix : SQLMigration() {
|
||||||
fun String.toSqlName(): String =
|
|
||||||
TransactionManager.defaultDatabase!!.identifierManager.let {
|
|
||||||
it.quoteIfNecessary(
|
|
||||||
it.inProperCase(this),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val CategoryMetaTable by lazy { "CategoryMeta".toSqlName() }
|
private val CategoryMetaTable by lazy { "CategoryMeta".toSqlName() }
|
||||||
private val CategoryRefColumn by lazy { "category_ref".toSqlName() }
|
private val CategoryRefColumn by lazy { "category_ref".toSqlName() }
|
||||||
private val CategoryTable by lazy { "Category".toSqlName() }
|
private val CategoryTable by lazy { "Category".toSqlName() }
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package suwayomi.tachidesk.server.database.migration
|
|||||||
* 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 de.neonew.exposed.migrations.helpers.SQLMigration
|
import de.neonew.exposed.migrations.helpers.SQLMigration
|
||||||
|
import suwayomi.tachidesk.server.database.migration.helpers.toSqlName
|
||||||
|
|
||||||
@Suppress("ClassName", "unused")
|
@Suppress("ClassName", "unused")
|
||||||
class M0049_FixDuplicatedMetas : SQLMigration() {
|
class M0049_FixDuplicatedMetas : SQLMigration() {
|
||||||
@@ -15,7 +16,7 @@ class M0049_FixDuplicatedMetas : SQLMigration() {
|
|||||||
table: String,
|
table: String,
|
||||||
refColumn: String? = null,
|
refColumn: String? = null,
|
||||||
): String {
|
): String {
|
||||||
val groupBy = listOfNotNull(refColumn, "KEY").joinToString(", ")
|
val groupBy = listOfNotNull(refColumn, "KEY".toSqlName()).joinToString(", ")
|
||||||
|
|
||||||
return """
|
return """
|
||||||
DELETE FROM $table
|
DELETE FROM $table
|
||||||
@@ -30,10 +31,11 @@ class M0049_FixDuplicatedMetas : SQLMigration() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val sql: String =
|
override val sql: String by lazy {
|
||||||
createMigrationForTable("CATEGORYMETA", "CATEGORY_REF") +
|
createMigrationForTable("CATEGORYMETA", "CATEGORY_REF") +
|
||||||
createMigrationForTable("CHAPTERMETA", "CHAPTER_REF") +
|
createMigrationForTable("CHAPTERMETA", "CHAPTER_REF") +
|
||||||
createMigrationForTable("GLOBALMETA") +
|
createMigrationForTable("GLOBALMETA") +
|
||||||
createMigrationForTable("MANGAMETA", "MANGA_REF") +
|
createMigrationForTable("MANGAMETA", "MANGA_REF") +
|
||||||
createMigrationForTable("SOURCEMETA", "SOURCE_REF")
|
createMigrationForTable("SOURCEMETA", "SOURCE_REF")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
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.SQLMigration
|
||||||
|
import suwayomi.tachidesk.graphql.types.DatabaseType
|
||||||
|
import suwayomi.tachidesk.server.database.migration.helpers.toSqlName
|
||||||
|
import suwayomi.tachidesk.server.serverConfig
|
||||||
|
|
||||||
|
@Suppress("ClassName", "unused")
|
||||||
|
class M0055_RenameMetaKeys : SQLMigration() {
|
||||||
|
fun postgresRename(table: String): String =
|
||||||
|
"ALTER TABLE $table " +
|
||||||
|
"RENAME COLUMN " + "KEY".toSqlName() + " TO META_KEY;"
|
||||||
|
|
||||||
|
fun h2Rename(table: String): String =
|
||||||
|
"ALTER TABLE $table " +
|
||||||
|
"ALTER COLUMN " + "KEY".toSqlName() + " RENAME TO META_KEY;"
|
||||||
|
|
||||||
|
fun createRenameMigration(table: String): String =
|
||||||
|
when (serverConfig.databaseType.value) {
|
||||||
|
DatabaseType.H2 -> h2Rename(table.toSqlName())
|
||||||
|
DatabaseType.POSTGRESQL -> postgresRename(table.toSqlName())
|
||||||
|
}
|
||||||
|
|
||||||
|
override val sql: String by lazy {
|
||||||
|
createRenameMigration("CATEGORYMETA") +
|
||||||
|
createRenameMigration("CHAPTERMETA") +
|
||||||
|
createRenameMigration("GLOBALMETA") +
|
||||||
|
createRenameMigration("MANGAMETA") +
|
||||||
|
createRenameMigration("SOURCEMETA")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,9 @@
|
|||||||
package suwayomi.tachidesk.server.database.migration.helpers
|
package suwayomi.tachidesk.server.database.migration.helpers
|
||||||
|
|
||||||
import de.neonew.exposed.migrations.helpers.SQLMigration
|
import de.neonew.exposed.migrations.helpers.SQLMigration
|
||||||
import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager
|
|
||||||
import suwayomi.tachidesk.graphql.types.DatabaseType
|
import suwayomi.tachidesk.graphql.types.DatabaseType
|
||||||
import suwayomi.tachidesk.server.serverConfig
|
import suwayomi.tachidesk.server.serverConfig
|
||||||
|
|
||||||
fun String.toSqlName(): String =
|
|
||||||
TransactionManager.current().db.identifierManager.let {
|
|
||||||
it.quoteIfNecessary(
|
|
||||||
it.inProperCase(this),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class RenameFieldMigration(
|
abstract class RenameFieldMigration(
|
||||||
tableName: String,
|
tableName: String,
|
||||||
originalName: String,
|
originalName: String,
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package suwayomi.tachidesk.server.database.migration.helpers
|
||||||
|
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager
|
||||||
|
|
||||||
|
fun String.toSqlName(): String =
|
||||||
|
TransactionManager.current().db.identifierManager.let {
|
||||||
|
it.quoteIfNecessary(
|
||||||
|
it.inProperCase(this),
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user