diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 72ab179d..5e332ca6 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -23,6 +23,18 @@ jobs: name: Build pull request needs: check_wrapper runs-on: ubuntu-latest + services: + postgres: + image: postgres + env: + POSTGRES_PASSWORD: postgres + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 steps: - name: Checkout pull request @@ -47,7 +59,39 @@ jobs: mkdir -p ~/.gradle cp .github/runner-files/ci-gradle.properties ~/.gradle/gradle.properties - - name: Build Jar + - name: Build And Run Jar working-directory: master - run: ./gradlew ktlintCheck :server:shadowJar --stacktrace + run: | + ./gradlew ktlintCheck :server:shadowJar --stacktrace + gcc -fPIC -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -shared scripts/resources/catch_abort.c -lpthread -o scripts/resources/catch_abort.so + export LD_PRELOAD="$(pwd)/scripts/resources/catch_abort.so" + JAR=$(ls ./server/build/*.jar| head -1) + set +e + timeout 30s java -DcrashOnFailedMigration=true \ + -Dsuwayomi.tachidesk.config.server.systemTrayEnabled=false \ + -Dsuwayomi.tachidesk.config.server.initialOpenInBrowserEnabled=false \ + -Dsuwayomi.tachidesk.config.server.databaseType=POSTGRESQL \ + -Dsuwayomi.tachidesk.config.server.databaseUrl=postgresql://localhost:5432/postgres \ + -Dsuwayomi.tachidesk.config.server.databaseUsername=postgres \ + -Dsuwayomi.tachidesk.config.server.databasePassword=postgres \ + -jar "$JAR" + ecode="$?" + # if exit code is not 124 or 125, then error + if ! [ "$ecode" -eq 124 -o "$ecode" -eq 125 ]; then + printf "exit code '%s' - exiting.\n" "$ecode" + exit "$ecode" + fi + + timeout 30s java -DcrashOnFailedMigration=true \ + -Dsuwayomi.tachidesk.config.server.systemTrayEnabled=false \ + -Dsuwayomi.tachidesk.config.server.initialOpenInBrowserEnabled=false \ + -jar "$JAR" + + ecode="$?" + # if exit code is not 124 or 125, then error + if ! [ "$ecode" -eq 124 -o "$ecode" -eq 125 ]; then + printf "exit code '%s' - exiting.\n" "$ecode" + exit "$ecode" + fi + exit 0 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ab0fa790..a4a8bb6c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -67,6 +67,7 @@ exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "e exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" } exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" } exposed-javatime = { module = "org.jetbrains.exposed:exposed-java-time", version.ref = "exposed" } +postgres = "org.postgresql:postgresql:42.7.7" h2 = "com.h2database:h2:1.4.200" # current database driver, can't update to h2 v2 without sql migration # Exposed Migrations diff --git a/server/build.gradle.kts b/server/build.gradle.kts index 2906f186..f3cdd99b 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -52,6 +52,7 @@ dependencies { // Exposed ORM implementation(libs.bundles.exposed) + implementation(libs.postgres) implementation(libs.h2) // Exposed Migrations diff --git a/server/server-config/src/main/kotlin/suwayomi/tachidesk/graphql/types/DatabaseType.kt b/server/server-config/src/main/kotlin/suwayomi/tachidesk/graphql/types/DatabaseType.kt new file mode 100644 index 00000000..dc2767a8 --- /dev/null +++ b/server/server-config/src/main/kotlin/suwayomi/tachidesk/graphql/types/DatabaseType.kt @@ -0,0 +1,6 @@ +package suwayomi.tachidesk.graphql.types + +enum class DatabaseType { + H2, + POSTGRESQL, +} diff --git a/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt b/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt index 480ab5eb..08f518b0 100644 --- a/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt +++ b/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt @@ -24,6 +24,7 @@ import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach import org.jetbrains.exposed.sql.SortOrder import suwayomi.tachidesk.graphql.types.AuthMode +import suwayomi.tachidesk.graphql.types.DatabaseType import suwayomi.tachidesk.graphql.types.DownloadConversion import suwayomi.tachidesk.graphql.types.KoreaderSyncChecksumMethod import suwayomi.tachidesk.graphql.types.KoreaderSyncStrategy @@ -636,6 +637,32 @@ class ServerConfig( requiresRestart = true, ) + val databaseType: MutableStateFlow by EnumSetting( + protoNumber = 69, + group = SettingGroup.DATABASE, + defaultValue = DatabaseType.H2, + enumClass = DatabaseType::class, + typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("suwayomi.tachidesk.graphql.types.DatabaseType")), + ) + + val databaseUrl: MutableStateFlow by StringSetting( + protoNumber = 70, + group = SettingGroup.DATABASE, + defaultValue = "postgresql://localhost:5432/suwayomi", + ) + + val databaseUsername: MutableStateFlow by StringSetting( + protoNumber = 71, + group = SettingGroup.DATABASE, + defaultValue = "", + ) + + val databasePassword: MutableStateFlow by StringSetting( + protoNumber = 72, + group = SettingGroup.DATABASE, + defaultValue = "", + ) + /** ****************************************************************** **/ /** **/ /** Renamed settings **/ diff --git a/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/settings/SettingGroup.kt b/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/settings/SettingGroup.kt index 5ae1d5a8..5a329e3d 100644 --- a/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/settings/SettingGroup.kt +++ b/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/settings/SettingGroup.kt @@ -4,6 +4,7 @@ enum class SettingGroup( val value: String, ) { NETWORK("Network"), + DATABASE("Database"), PROXY("Proxy"), WEB_UI("WebUI"), DOWNLOADER("Downloader"), diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt index d300454e..87c46939 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt @@ -72,7 +72,7 @@ class JavalinGraphQLRequestParser : GraphQLRequestParser { ) } } - } catch (e: IOException) { + } catch (_: IOException) { null } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryTable.kt index 8bca5368..c60facca 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryTable.kt @@ -15,7 +15,7 @@ import suwayomi.tachidesk.manga.model.dataclass.IncludeOrExclude object CategoryTable : IntIdTable() { val name = varchar("name", 64) - val order = integer("order").default(0) + val order = integer("sort_order").default(0) val isDefault = bool("is_default").default(false) val includeInUpdate = integer("include_in_update").default(IncludeOrExclude.UNSET.value) val includeInDownload = integer("include_in_download").default(IncludeOrExclude.UNSET.value) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaTable.kt index e0924c6f..e17b73b7 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaTable.kt @@ -17,16 +17,17 @@ import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass import suwayomi.tachidesk.manga.model.dataclass.toGenreList import suwayomi.tachidesk.manga.model.table.MangaStatus.Companion import suwayomi.tachidesk.manga.model.table.columns.truncatingVarchar +import suwayomi.tachidesk.manga.model.table.columns.unlimitedVarchar object MangaTable : IntIdTable() { val url = varchar("url", 2048) val title = truncatingVarchar("title", 512) val initialized = bool("initialized").default(false) - val artist = truncatingVarchar("artist", Integer.MAX_VALUE).nullable() - val author = truncatingVarchar("author", Integer.MAX_VALUE).nullable() - val description = truncatingVarchar("description", Integer.MAX_VALUE).nullable() - val genre = truncatingVarchar("genre", Integer.MAX_VALUE).nullable() + val artist = unlimitedVarchar("artist").nullable() + val author = unlimitedVarchar("author").nullable() + val description = unlimitedVarchar("description").nullable() + val genre = unlimitedVarchar("genre").nullable() val status = integer("status").default(SManga.UNKNOWN) val thumbnail_url = varchar("thumbnail_url", 2048).nullable() diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/PageTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/PageTable.kt index d0a53c56..6135dc91 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/PageTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/PageTable.kt @@ -9,11 +9,12 @@ package suwayomi.tachidesk.manga.model.table import org.jetbrains.exposed.dao.id.IntIdTable import org.jetbrains.exposed.sql.ReferenceOption +import suwayomi.tachidesk.manga.model.table.columns.unlimitedVarchar object PageTable : IntIdTable() { val index = integer("index") val url = varchar("url", 2048) - val imageUrl = varchar("image_url", Integer.MAX_VALUE).nullable() + val imageUrl = unlimitedVarchar("image_url").nullable() val chapter = reference("chapter", ChapterTable, ReferenceOption.CASCADE) } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/columns/TruncatingVarCharColumn.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/columns/TruncatingVarCharColumn.kt index bcadbd0f..b5c897fa 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/columns/TruncatingVarCharColumn.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/columns/TruncatingVarCharColumn.kt @@ -4,6 +4,8 @@ import io.github.oshai.kotlinlogging.KotlinLogging import org.jetbrains.exposed.sql.Column import org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.VarCharColumnType +import suwayomi.tachidesk.graphql.types.DatabaseType +import suwayomi.tachidesk.server.serverConfig class TruncatingVarCharColumn( private val table: String, @@ -34,3 +36,12 @@ fun Table.truncatingVarchar( length: Int, collate: String? = null, ): Column = registerColumn(name, TruncatingVarCharColumn(this.tableName, name, length, collate)) + +fun Table.unlimitedVarchar( + name: String, + collate: String? = null, +): Column = + when (serverConfig.databaseType.value) { + DatabaseType.H2 -> truncatingVarchar(name, Int.MAX_VALUE, collate) + DatabaseType.POSTGRESQL -> text(name, collate) + } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt index a9825aaa..78b34cd1 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt @@ -38,6 +38,7 @@ import org.koin.core.module.Module import org.koin.dsl.module import suwayomi.tachidesk.global.impl.KcefWebView.Companion.toCefCookie import suwayomi.tachidesk.graphql.types.AuthMode +import suwayomi.tachidesk.graphql.types.DatabaseType import suwayomi.tachidesk.i18n.LocalizationHelper import suwayomi.tachidesk.manga.impl.backup.proto.ProtoBackupExport import suwayomi.tachidesk.manga.impl.download.DownloadManager @@ -114,6 +115,13 @@ data class ProxySettings( val proxyPassword: String, ) +data class DatabaseSettings( + val databaseType: DatabaseType, + val databaseUrl: String, + val databaseUsername: String, + val databasePassword: String, +) + val serverConfig: ServerConfig by lazy { GlobalConfigManager.module() } val androidCompat by lazy { AndroidCompat() } @@ -365,6 +373,31 @@ fun applicationSetup() { LocalSource.register() + serverConfig.subscribeTo( + combine( + serverConfig.databaseType, + serverConfig.databaseUrl, + serverConfig.databaseUsername, + serverConfig.databasePassword, + ) { vargs -> + DatabaseSettings( + vargs[0] as DatabaseType, + vargs[1] as String, + vargs[2] as String, + vargs[3] as String, + ) + }.distinctUntilChanged(), + { (databaseType, databaseUrl, databaseUsername, _) -> + logger.info { + "Database changed - type=$databaseType url=$databaseUrl, username=$databaseUsername, password=[REDACTED]" + } + databaseUp() + + LocalSource.register() + }, + ignoreInitialValue = true, + ) + // create system tray serverConfig.subscribeTo( serverConfig.systemTrayEnabled, diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt index ba616d93..9421919f 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt @@ -13,35 +13,84 @@ import io.github.oshai.kotlinlogging.KotlinLogging import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.DatabaseConfig import org.jetbrains.exposed.sql.ExperimentalKeywordApi +import org.jetbrains.exposed.sql.Schema +import org.jetbrains.exposed.sql.SchemaUtils +import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.jetbrains.exposed.sql.transactions.transaction +import suwayomi.tachidesk.graphql.types.DatabaseType import suwayomi.tachidesk.server.ApplicationDirs import suwayomi.tachidesk.server.ServerConfig +import suwayomi.tachidesk.server.serverConfig import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import java.sql.SQLException +import kotlin.system.exitProcess object DBManager { - val db by lazy { + var db: Database? = null + private set + + fun setupDatabase(): Database { + if (TransactionManager.isInitialized()) { + val currentDatabase = TransactionManager.currentOrNull()?.db + if (currentDatabase != null) { + TransactionManager.closeAndUnregister(currentDatabase) + } + } + val applicationDirs = Injekt.get() - Database.connect( - "jdbc:h2:${applicationDirs.dataRoot}/database", - "org.h2.Driver", - databaseConfig = - DatabaseConfig { - useNestedTransactions = true - @OptIn(ExperimentalKeywordApi::class) - preserveKeywordCasing = false - }, - ) + val dbConfig = + DatabaseConfig { + useNestedTransactions = true + @OptIn(ExperimentalKeywordApi::class) + preserveKeywordCasing = false + } + return when (serverConfig.databaseType.value) { + DatabaseType.POSTGRESQL -> + Database.connect( + "jdbc:${serverConfig.databaseUrl.value}", + "org.postgresql.Driver", + user = serverConfig.databaseUsername.value, + password = serverConfig.databasePassword.value, + databaseConfig = dbConfig, + ) + DatabaseType.H2 -> + Database.connect( + "jdbc:h2:${applicationDirs.dataRoot}/database", + "org.h2.Driver", + databaseConfig = dbConfig, + ) + }.also { db = it } } } private val logger = KotlinLogging.logger {} -fun databaseUp(db: Database = DBManager.db) { +fun databaseUp() { + val db = DBManager.setupDatabase() // call db to initialize the lazy object logger.info { "Using ${db.vendor} database version ${db.version}" } - val migrations = loadMigrationsFrom("suwayomi.tachidesk.server.database.migration", ServerConfig::class.java) - runMigrations(migrations) + try { + if (serverConfig.databaseType.value == DatabaseType.POSTGRESQL) { + transaction { + val schema = + Schema( + "suwayomi", + serverConfig.databaseUsername.value.takeIf { it.isNotBlank() }, + ) + SchemaUtils.createSchema(schema) + SchemaUtils.setSchema(schema) + } + } + val migrations = loadMigrationsFrom("suwayomi.tachidesk.server.database.migration", ServerConfig::class.java) + runMigrations(migrations) + } catch (e: SQLException) { + logger.error(e) { "Error up-to-database migration" } + if (System.getProperty("crashOnFailedMigration").toBoolean()) { + exitProcess(101) + } + } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0002_ChapterTableIndexRename.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0002_ChapterTableIndexRename.kt index d0829c7f..86598526 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0002_ChapterTableIndexRename.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0002_ChapterTableIndexRename.kt @@ -1,5 +1,7 @@ package suwayomi.tachidesk.server.database.migration +import suwayomi.tachidesk.server.database.migration.helpers.RenameFieldMigration + /* * Copyright (C) Contributors to the Suwayomi project * @@ -7,8 +9,6 @@ package suwayomi.tachidesk.server.database.migration * 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.RenameFieldMigration - @Suppress("ClassName", "unused") class M0002_ChapterTableIndexRename : RenameFieldMigration( diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0003_DefaultCategory.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0003_DefaultCategory.kt index 17f5ecf9..e72e13b0 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0003_DefaultCategory.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0003_DefaultCategory.kt @@ -1,5 +1,7 @@ package suwayomi.tachidesk.server.database.migration +import suwayomi.tachidesk.server.database.migration.helpers.RenameFieldMigration + /* * Copyright (C) Contributors to the Suwayomi project * @@ -7,8 +9,6 @@ package suwayomi.tachidesk.server.database.migration * 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.RenameFieldMigration - @Suppress("ClassName", "unused") class M0003_DefaultCategory : RenameFieldMigration( diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0014_MangaRemoveLengthLimit.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0014_MangaRemoveLengthLimit.kt index 3a58fe3b..29d0f853 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0014_MangaRemoveLengthLimit.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0014_MangaRemoveLengthLimit.kt @@ -8,14 +8,16 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.SQLMigration +import suwayomi.tachidesk.server.database.migration.helpers.MAYBE_TYPE_PREFIX +import suwayomi.tachidesk.server.database.migration.helpers.UNLIMITED_TEXT @Suppress("ClassName", "unused") class M0014_MangaRemoveLengthLimit : SQLMigration() { override val sql = """ - ALTER TABLE MANGA ALTER COLUMN ARTIST VARCHAR(512); - ALTER TABLE MANGA ALTER COLUMN AUTHOR VARCHAR(512); - ALTER TABLE MANGA ALTER COLUMN DESCRIPTION VARCHAR; -- the default length is `Integer.MAX_VALUE` - ALTER TABLE MANGA ALTER COLUMN GENRE VARCHAR; -- the default length is `Integer.MAX_VALUE` + ALTER TABLE MANGA ALTER COLUMN ARTIST ${MAYBE_TYPE_PREFIX}VARCHAR(512); + ALTER TABLE MANGA ALTER COLUMN AUTHOR ${MAYBE_TYPE_PREFIX}VARCHAR(512); + ALTER TABLE MANGA ALTER COLUMN DESCRIPTION ${MAYBE_TYPE_PREFIX}$UNLIMITED_TEXT; -- the default length is `Integer.MAX_VALUE` + ALTER TABLE MANGA ALTER COLUMN GENRE ${MAYBE_TYPE_PREFIX}$UNLIMITED_TEXT; -- the default length is `Integer.MAX_VALUE` """.trimIndent() } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0015_SourceAndExtensionLangAddLengthLimit.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0015_SourceAndExtensionLangAddLengthLimit.kt index d8678505..6e4f7162 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0015_SourceAndExtensionLangAddLengthLimit.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0015_SourceAndExtensionLangAddLengthLimit.kt @@ -8,12 +8,13 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.SQLMigration +import suwayomi.tachidesk.server.database.migration.helpers.MAYBE_TYPE_PREFIX @Suppress("ClassName", "unused") class M0015_SourceAndExtensionLangAddLengthLimit : SQLMigration() { override val sql = """ - ALTER TABLE SOURCE ALTER COLUMN LANG VARCHAR(32); - ALTER TABLE EXTENSION ALTER COLUMN LANG VARCHAR(32); + ALTER TABLE SOURCE ALTER COLUMN LANG ${MAYBE_TYPE_PREFIX}VARCHAR(32); + ALTER TABLE EXTENSION ALTER COLUMN LANG ${MAYBE_TYPE_PREFIX}VARCHAR(32); """.trimIndent() } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0016_ChapterIndexRenameToSourceOrder.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0016_ChapterIndexRenameToSourceOrder.kt index 037353f2..ae043c37 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0016_ChapterIndexRenameToSourceOrder.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0016_ChapterIndexRenameToSourceOrder.kt @@ -7,12 +7,12 @@ package suwayomi.tachidesk.server.database.migration * 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.server.database.migration.helpers.RenameFieldMigration @Suppress("ClassName", "unused") -class M0016_ChapterIndexRenameToSourceOrder : SQLMigration() { - override val sql = - """ - ALTER TABLE CHAPTER ALTER COLUMN INDEX RENAME TO SOURCE_ORDER; - """.trimIndent() -} +class M0016_ChapterIndexRenameToSourceOrder : + RenameFieldMigration( + "CHAPTER", + "INDEX", + "SOURCE_ORDER", + ) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0027_AddDefaultCategory.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0027_AddDefaultCategory.kt index 5cd1577b..71ac2b6b 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0027_AddDefaultCategory.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0027_AddDefaultCategory.kt @@ -1,6 +1,7 @@ package suwayomi.tachidesk.server.database.migration import de.neonew.exposed.migrations.helpers.SQLMigration +import suwayomi.tachidesk.server.database.migration.helpers.INITIAL_ORDER_NAME /* * Copyright (C) Contributors to the Suwayomi project @@ -13,6 +14,6 @@ import de.neonew.exposed.migrations.helpers.SQLMigration 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) + INSERT INTO CATEGORY (ID, NAME, IS_DEFAULT, $INITIAL_ORDER_NAME, INCLUDE_IN_UPDATE) VALUES (0, 'Default', TRUE, 0, -1) """.trimIndent() } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0042_MangaRemoveLengthLimit_II.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0042_MangaRemoveLengthLimit_II.kt index 110cbbe9..ce50d03f 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0042_MangaRemoveLengthLimit_II.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0042_MangaRemoveLengthLimit_II.kt @@ -8,12 +8,14 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.SQLMigration +import suwayomi.tachidesk.server.database.migration.helpers.MAYBE_TYPE_PREFIX +import suwayomi.tachidesk.server.database.migration.helpers.UNLIMITED_TEXT @Suppress("ClassName", "unused") class M0042_MangaRemoveLengthLimit_II : SQLMigration() { override val sql = """ - ALTER TABLE MANGA ALTER COLUMN ARTIST VARCHAR; -- the default length is `Integer.MAX_VALUE` - ALTER TABLE MANGA ALTER COLUMN AUTHOR VARCHAR; -- the default length is `Integer.MAX_VALUE` + ALTER TABLE MANGA ALTER COLUMN ARTIST $MAYBE_TYPE_PREFIX$UNLIMITED_TEXT; -- the default length is `Integer.MAX_VALUE` + ALTER TABLE MANGA ALTER COLUMN AUTHOR $MAYBE_TYPE_PREFIX$UNLIMITED_TEXT; -- the default length is `Integer.MAX_VALUE` """.trimIndent() } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0046_RenamePageImageUrlColumn.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0046_RenamePageImageUrlColumn.kt index 223a19bd..520404d6 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0046_RenamePageImageUrlColumn.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0046_RenamePageImageUrlColumn.kt @@ -1,5 +1,7 @@ package suwayomi.tachidesk.server.database.migration +import suwayomi.tachidesk.server.database.migration.helpers.RenameFieldMigration + /* * Copyright (C) Contributors to the Suwayomi project * @@ -7,8 +9,6 @@ package suwayomi.tachidesk.server.database.migration * 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.RenameFieldMigration - @Suppress("ClassName", "unused") class M0046_RenamePageImageUrlColumn : RenameFieldMigration( diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0047_ChapterScanlatorIncreaseLength.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0047_ChapterScanlatorIncreaseLength.kt index adcada0c..17abf166 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0047_ChapterScanlatorIncreaseLength.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0047_ChapterScanlatorIncreaseLength.kt @@ -8,11 +8,12 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.SQLMigration +import suwayomi.tachidesk.server.database.migration.helpers.MAYBE_TYPE_PREFIX @Suppress("ClassName", "unused") class M0047_ChapterScanlatorIncreaseLength : SQLMigration() { override val sql = """ - ALTER TABLE CHAPTER ALTER COLUMN SCANLATOR VARCHAR(256); + ALTER TABLE CHAPTER ALTER COLUMN SCANLATOR ${MAYBE_TYPE_PREFIX}VARCHAR(256); """.trimIndent() } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0050_FixHandlingOfTooLongPageImageUrls.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0050_FixHandlingOfTooLongPageImageUrls.kt index 48f4f940..73fbf7e5 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0050_FixHandlingOfTooLongPageImageUrls.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0050_FixHandlingOfTooLongPageImageUrls.kt @@ -8,6 +8,8 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.SQLMigration +import suwayomi.tachidesk.server.database.migration.helpers.MAYBE_TYPE_PREFIX +import suwayomi.tachidesk.server.database.migration.helpers.UNLIMITED_TEXT @Suppress("ClassName", "unused") class M0050_FixHandlingOfTooLongPageImageUrls : SQLMigration() { @@ -23,6 +25,6 @@ class M0050_FixHandlingOfTooLongPageImageUrls : SQLMigration() { ALTER TABLE PAGE DROP CONSTRAINT IF EXISTS UC_PAGE; ALTER TABLE PAGE ADD CONSTRAINT UC_PAGE UNIQUE (INDEX, CHAPTER); - ALTER TABLE PAGE ALTER COLUMN IMAGE_URL VARCHAR; -- the default length is `Integer.MAX_VALUE` + ALTER TABLE PAGE ALTER COLUMN IMAGE_URL $MAYBE_TYPE_PREFIX$UNLIMITED_TEXT; -- the default length is `Integer.MAX_VALUE` """.trimIndent() } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0052_RenameCategoryOrderColumn.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0052_RenameCategoryOrderColumn.kt new file mode 100644 index 00000000..1e91e6cf --- /dev/null +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0052_RenameCategoryOrderColumn.kt @@ -0,0 +1,19 @@ +package suwayomi.tachidesk.server.database.migration + +import suwayomi.tachidesk.server.database.migration.helpers.INITIAL_ORDER_NAME +import suwayomi.tachidesk.server.database.migration.helpers.RenameFieldMigration + +/* + * 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 M0052_RenameCategoryOrderColumn : + RenameFieldMigration( + "Category", + INITIAL_ORDER_NAME, + "sort_order", + ) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/RenameFieldMigration.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/RenameFieldMigration.kt new file mode 100644 index 00000000..c2f5bb79 --- /dev/null +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/RenameFieldMigration.kt @@ -0,0 +1,38 @@ +package suwayomi.tachidesk.server.database.migration.helpers + +import de.neonew.exposed.migrations.helpers.SQLMigration +import org.jetbrains.exposed.sql.transactions.TransactionManager +import suwayomi.tachidesk.graphql.types.DatabaseType +import suwayomi.tachidesk.server.serverConfig + +fun String.toSqlName(): String = + TransactionManager.current().db.identifierManager.let { + it.quoteIfNecessary( + it.inProperCase(this), + ) + } + +abstract class RenameFieldMigration( + tableName: String, + originalName: String, + newName: String, +) : SQLMigration() { + private val fixedTableName by lazy { tableName.toSqlName() } + private val fixedOriginalName by lazy { originalName.toSqlName() } + private val fixedNewName by lazy { newName.toSqlName() } + + fun postgresRename(): String = + "ALTER TABLE $fixedTableName " + + "RENAME COLUMN $fixedOriginalName TO $fixedNewName;" + + fun h2Rename(): String = + "ALTER TABLE $fixedTableName " + + "ALTER COLUMN $fixedOriginalName RENAME TO $fixedNewName" + + override val sql by lazy { + when (serverConfig.databaseType.value) { + DatabaseType.H2 -> h2Rename() + DatabaseType.POSTGRESQL -> postgresRename() + } + } +} diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/TypeHelpers.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/TypeHelpers.kt new file mode 100644 index 00000000..b8c5f562 --- /dev/null +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/TypeHelpers.kt @@ -0,0 +1,25 @@ +package suwayomi.tachidesk.server.database.migration.helpers + +import suwayomi.tachidesk.graphql.types.DatabaseType +import suwayomi.tachidesk.server.serverConfig + +val UNLIMITED_TEXT + get() = + when (serverConfig.databaseType.value) { + DatabaseType.H2 -> "VARCHAR" // the default length is `Integer.MAX_VALUE` + DatabaseType.POSTGRESQL -> "TEXT" + } + +val MAYBE_TYPE_PREFIX + get() = + when (serverConfig.databaseType.value) { + DatabaseType.H2 -> "" + DatabaseType.POSTGRESQL -> "TYPE " + } + +val INITIAL_ORDER_NAME + get() = + when (serverConfig.databaseType.value) { + DatabaseType.H2 -> """"ORDER"""" + DatabaseType.POSTGRESQL -> """"order"""" + }