From 74de3d60e301fef7706f8d233252089b7a8b915d Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Sun, 26 Oct 2025 12:07:50 +0100 Subject: [PATCH] Refactor DB Code --- src/main/kotlin/commands/SteamWar.kt | 6 +- .../commands/database/DatabaseCommand.kt | 4 +- .../kotlin/commands/database/InfoCommand.kt | 6 +- .../kotlin/commands/database/ResetCommand.kt | 10 ++- src/main/kotlin/commands/dev/DevCommand.kt | 18 ++--- .../kotlin/commands/user/UserInfoCommand.kt | 75 +++++++++---------- .../kotlin/commands/user/UserSearchCommand.kt | 4 +- src/main/kotlin/db/Database.kt | 75 ++++++++++--------- 8 files changed, 94 insertions(+), 104 deletions(-) diff --git a/src/main/kotlin/commands/SteamWar.kt b/src/main/kotlin/commands/SteamWar.kt index d87e975..4335c14 100644 --- a/src/main/kotlin/commands/SteamWar.kt +++ b/src/main/kotlin/commands/SteamWar.kt @@ -1,14 +1,10 @@ package de.steamwar.commands import com.github.ajalt.clikt.core.CliktCommand -import com.github.ajalt.clikt.core.findOrSetObject import com.github.ajalt.mordant.rendering.TextStyles -import de.steamwar.db.Database class SteamWar: CliktCommand(name = "sw") { - val db by findOrSetObject { Database() } - override fun run() { - echo("${TextStyles.bold("SteamWar-CLI")} (${db.database})") + echo(TextStyles.bold("SteamWar-CLI")) } } \ No newline at end of file diff --git a/src/main/kotlin/commands/database/DatabaseCommand.kt b/src/main/kotlin/commands/database/DatabaseCommand.kt index 9c2e5ec..d00068f 100644 --- a/src/main/kotlin/commands/database/DatabaseCommand.kt +++ b/src/main/kotlin/commands/database/DatabaseCommand.kt @@ -3,14 +3,14 @@ package de.steamwar.commands.database import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.CliktError import com.github.ajalt.clikt.core.Context -import com.github.ajalt.clikt.core.requireObject +import com.github.ajalt.clikt.core.findOrSetObject import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option import de.steamwar.db.Database class DatabaseCommand: CliktCommand(name = "db") { val useProduction by option().flag() - val db by requireObject() + val db by findOrSetObject { Database } override fun help(context: Context): String = "Run database commands" diff --git a/src/main/kotlin/commands/database/InfoCommand.kt b/src/main/kotlin/commands/database/InfoCommand.kt index 9942e0e..f14d29a 100644 --- a/src/main/kotlin/commands/database/InfoCommand.kt +++ b/src/main/kotlin/commands/database/InfoCommand.kt @@ -4,12 +4,14 @@ import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.requireObject import com.github.ajalt.mordant.table.table import de.steamwar.db.Database +import de.steamwar.db.execute +import de.steamwar.db.useDb class InfoCommand: CliktCommand() { val db by requireObject() - override fun run() { - val tables = db.execute("SHOW TABLES") { it.getString(1) } + override fun run() = useDb { + val tables = execute("SHOW TABLES") { it.getString(1) } echo( table { diff --git a/src/main/kotlin/commands/database/ResetCommand.kt b/src/main/kotlin/commands/database/ResetCommand.kt index 26fcac5..b78e3e1 100644 --- a/src/main/kotlin/commands/database/ResetCommand.kt +++ b/src/main/kotlin/commands/database/ResetCommand.kt @@ -6,12 +6,14 @@ import com.github.ajalt.clikt.core.requireObject import com.github.ajalt.mordant.rendering.TextColors import com.github.ajalt.mordant.rendering.TextStyles import de.steamwar.db.Database +import de.steamwar.db.execute +import de.steamwar.db.useDb import java.io.File class ResetCommand: CliktCommand() { val db by requireObject() - override fun run() { + override fun run() = useDb { val schemaFile = File("/var/Schema.sql") if (!schemaFile.exists()) { throw CliktError("Schema file not found!") @@ -19,12 +21,12 @@ class ResetCommand: CliktCommand() { val schema = schemaFile.readText() - val tables = db.execute("SHOW TABLES;") { it.getString(1) } + val tables = execute("SHOW TABLES;") { it.getString(1) } for (table in tables) { - db.execute("DROP TABLE IF EXISTS $table;") { } + execute("DROP TABLE IF EXISTS $table;") { } } - db.execute(schema) { } + execute(schema) { } echo(TextColors.brightGreen(TextStyles.bold("Database reset!"))) } diff --git a/src/main/kotlin/commands/dev/DevCommand.kt b/src/main/kotlin/commands/dev/DevCommand.kt index dee2314..32cdcfd 100644 --- a/src/main/kotlin/commands/dev/DevCommand.kt +++ b/src/main/kotlin/commands/dev/DevCommand.kt @@ -7,6 +7,7 @@ import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.help import com.github.ajalt.clikt.parameters.arguments.multiple import com.github.ajalt.clikt.parameters.options.default +import com.github.ajalt.clikt.parameters.options.defaultLazy import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.option @@ -51,15 +52,13 @@ class DevCommand : CliktCommand("dev") { override val treatUnknownOptionsAsArgs = true val server by argument().help("Server Template") - val port by option("--port").long().default( - if (System.getProperty("os.name").lowercase() == "windows" - ) 2050 else (UnixSystem().uid + 1010) - ).help("Port for Server") + val port by option("--port").long().defaultLazy { UnixSystem().uid + 1010 }.help("Port for Server") val world by option("--world", "-w").path(canBeFile = false).help("User World") val plugins by option("--plugins", "-p").path(true, canBeFile = false).help("Plugin Dir") val profile by option().flag().help("Add Profiling Arguments") val forceUpgrade by option().flag().help("Force Upgrade") val jar by option().file(true, canBeDir = false).help("Jar File") + val jvm by option().file(true, canBeDir = false).help("Java Executable") val jvmArgs by argument().multiple() override val printHelpOnEmptyArgs = true @@ -110,8 +109,7 @@ class DevCommand : CliktCommand("dev") { try { devFile.delete() - } catch (_: Exception) { - } + } catch (_: Exception) { /* ignored */ } } } @@ -164,8 +162,8 @@ class DevCommand : CliktCommand("dev") { } fun runServer(args: List, jvmArgs: List, cmd: List, serverDir: File) { - val command = arrayOf( - if (isJava8(server)) "/usr/lib/jvm/openj9-8/bin/java" else "java", + val process = ProcessBuilder( + jvm?.absolutePath ?: if (isJava8(server)) "/usr/lib/jvm/openj9-8/bin/java" else "java", *jvmArgs.toTypedArray(), *args.toTypedArray(), *jvmDefaultParams, @@ -174,10 +172,6 @@ class DevCommand : CliktCommand("dev") { "-Xshareclasses:nonfatal,name=$server", "-jar", *cmd.toTypedArray() - ) - echo(command.joinToString(" ")) - val process = ProcessBuilder( - *command ).directory(serverDir).inheritIO().start() process.waitFor() } diff --git a/src/main/kotlin/commands/user/UserInfoCommand.kt b/src/main/kotlin/commands/user/UserInfoCommand.kt index 607f284..136c1e8 100644 --- a/src/main/kotlin/commands/user/UserInfoCommand.kt +++ b/src/main/kotlin/commands/user/UserInfoCommand.kt @@ -2,18 +2,14 @@ package de.steamwar.commands.user import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.CliktError -import com.github.ajalt.clikt.core.findOrSetObject import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.help import com.github.ajalt.mordant.table.table import de.steamwar.db.findUser import de.steamwar.db.schema.Session -import de.steamwar.db.schema.SteamwarUser -import de.steamwar.db.schema.SteamwarUserTable +import de.steamwar.db.useDb import org.jetbrains.exposed.v1.core.eq -import org.jetbrains.exposed.v1.core.or import org.jetbrains.exposed.v1.jdbc.selectAll -import org.jetbrains.exposed.v1.jdbc.transactions.transaction import kotlin.time.DurationUnit import kotlin.time.ExperimentalTime @@ -24,45 +20,44 @@ class UserInfoCommand : CliktCommand("info") { override val printHelpOnEmptyArgs = true @OptIn(ExperimentalTime::class) - override fun run() { - transaction { - val sessions = - Session.selectAll().where { Session.user eq user.id.value }.map { it[Session.start] to it[Session.end] } + override fun run() = useDb { + val sessions = + Session.selectAll().where { Session.user eq user.id.value }.map { it[Session.start] to it[Session.end] } - val totalPlayed = sessions.map { it.second - it.first }.sumOf { it.toDouble(DurationUnit.HOURS) } - val firstJoin = sessions.minByOrNull { it.first }?.first - val lastJoin = sessions.maxByOrNull { it.second }?.second + val totalPlayed = sessions.map { it.second - it.first }.sumOf { it.toDouble(DurationUnit.HOURS) } + val firstJoin = sessions.minByOrNull { it.first }?.first + val lastJoin = sessions.maxByOrNull { it.second }?.second - val punishments = user.punishments + val punishments = user.punishments - echo( - table { - body { - row("Name", user.username) - row("UUID", user.uuid) - row("Team", user.team.name) - row("Leader", user.leader) - row("Locale", user.locale) - row("Beigetreten am", firstJoin) - row("Zuletzt gesehen am", lastJoin) - row("Spielzeit", totalPlayed.toString() + "h") - row("Punishments", if (punishments.empty()) "Keine" else table { - header { row("Typ", "Ersteller", "Von", "Bis", "Grund") } - body { - punishments.map { - row( - it.type, - it.punisher.username, - it.starttime.toString(), - if (it.perma) "Perma" else it.endtime.toString(), - it.reason - ) - } + echo( + table { + body { + row("Name", user.username) + row("UUID", user.uuid) + row("Team", user.team.name) + row("Leader", user.leader) + row("Locale", user.locale) + row("Beigetreten am", firstJoin) + row("Zuletzt gesehen am", lastJoin) + row("Spielzeit", totalPlayed.toString() + "h") + row("Punishments", if (punishments.empty()) "Keine" else table { + header { row("Typ", "Ersteller", "Von", "Bis", "Grund") } + body { + punishments.map { + row( + it.type, + it.punisher.username, + it.starttime.toString(), + if (it.perma) "Perma" else it.endtime.toString(), + it.reason + ) } - }) - } + } + }) } - ) - } + } + ) + } } \ No newline at end of file diff --git a/src/main/kotlin/commands/user/UserSearchCommand.kt b/src/main/kotlin/commands/user/UserSearchCommand.kt index ec26f55..ff5106c 100644 --- a/src/main/kotlin/commands/user/UserSearchCommand.kt +++ b/src/main/kotlin/commands/user/UserSearchCommand.kt @@ -9,9 +9,9 @@ import de.steamwar.db.joinedOr import de.steamwar.db.schema.SteamwarUser import de.steamwar.db.schema.SteamwarUserTable import de.steamwar.db.schema.Team +import de.steamwar.db.useDb import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.v1.core.like -import org.jetbrains.exposed.v1.jdbc.transactions.transaction class UserSearchCommand : CliktCommand("search") { val query by argument().help("Name, Id, UUID or DiscordId") @@ -20,7 +20,7 @@ class UserSearchCommand : CliktCommand("search") { override fun help(context: Context): String = "Search for users" - override fun run() = transaction { + override fun run() = useDb { val users = SteamwarUser.find { joinedOr( SteamwarUserTable.username like "%$query%", diff --git a/src/main/kotlin/db/Database.kt b/src/main/kotlin/db/Database.kt index e889333..5be3b27 100644 --- a/src/main/kotlin/db/Database.kt +++ b/src/main/kotlin/db/Database.kt @@ -5,32 +5,26 @@ import com.github.ajalt.clikt.core.CliktError import de.steamwar.db.schema.SteamwarUser import de.steamwar.db.schema.SteamwarUserTable import org.jetbrains.exposed.v1.core.Expression -import org.jetbrains.exposed.v1.core.ExpressionWithColumnType -import org.jetbrains.exposed.v1.core.Function -import org.jetbrains.exposed.v1.core.IColumnType -import org.jetbrains.exposed.v1.core.LongColumnType import org.jetbrains.exposed.v1.core.Op -import org.jetbrains.exposed.v1.core.QueryBuilder -import org.jetbrains.exposed.v1.core.WindowFunction -import org.jetbrains.exposed.v1.core.WindowFunctionDefinition -import org.jetbrains.exposed.v1.core.append import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.v1.core.or import org.jetbrains.exposed.v1.jdbc.Database +import org.jetbrains.exposed.v1.jdbc.JdbcTransaction import org.jetbrains.exposed.v1.jdbc.transactions.transaction import java.io.File import java.sql.ResultSet import java.util.Properties -import java.util.UUID -import kotlin.time.ExperimentalTime -import kotlin.time.Instant -class Database { - val host: String - val port: String - val database: String +object Database { + lateinit var host: String + lateinit var port: String + lateinit var database: String + lateinit var db: Database - init { + fun ensureConnected() { + if (::db.isInitialized) { + return + } val config = File(System.getProperty("user.home"), "mysql.properties") if (!config.exists()) { @@ -50,26 +44,8 @@ class Database { val url = "jdbc:mariadb://$host:$port/$database" - Database.Companion.connect(url, driver = "org.mariadb.jdbc.Driver", user = username, password = password) - } - - fun execute(sql: String, transform: (ResultSet) -> T): List = transaction { - val result = mutableListOf() - exec(sql) { rs -> - while (rs.next()) { - result += transform(rs) - } - } - return@transaction result - } - - fun executeSingle(sql: String, transform: (ResultSet) -> T): T? { - return execute(sql) { rs -> - if (!rs.next()) { - return@execute null - } - transform(rs) - }.single() + db = Database.connect(url, driver = "org.mariadb.jdbc.Driver", user = username, password = password) + return } } @@ -80,4 +56,29 @@ fun > BaseCliktCommand.findUser(query: String): Steamw } fun joinedOr(vararg expressions: Expression?): Op = - expressions.filterNotNull().reduce { acc, expression -> acc or expression } as Op \ No newline at end of file + expressions.filterNotNull().reduce { acc, expression -> acc or expression } as Op + + +fun JdbcTransaction.execute(sql: String, transform: (ResultSet) -> T): List { + val result = mutableListOf() + exec(sql) { rs -> + while (rs.next()) { + result += transform(rs) + } + } + return result +} + +fun JdbcTransaction.executeSingle(sql: String, transform: (ResultSet) -> T): T? { + return execute(sql) { rs -> + if (!rs.next()) { + return@execute null + } + transform(rs) + }.single() +} + +fun useDb(statement: JdbcTransaction.() -> Unit) { + de.steamwar.db.Database.ensureConnected() + transaction(de.steamwar.db.Database.db, statement) +} \ No newline at end of file