Refactor DB Code
All checks were successful
SteamWarCI Build successful

This commit is contained in:
2025-10-26 12:07:50 +01:00
parent 7b5458cbd0
commit 74de3d60e3
8 changed files with 94 additions and 104 deletions

View File

@ -1,14 +1,10 @@
package de.steamwar.commands package de.steamwar.commands
import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.findOrSetObject
import com.github.ajalt.mordant.rendering.TextStyles import com.github.ajalt.mordant.rendering.TextStyles
import de.steamwar.db.Database
class SteamWar: CliktCommand(name = "sw") { class SteamWar: CliktCommand(name = "sw") {
val db by findOrSetObject { Database() }
override fun run() { override fun run() {
echo("${TextStyles.bold("SteamWar-CLI")} (${db.database})") echo(TextStyles.bold("SteamWar-CLI"))
} }
} }

View File

@ -3,14 +3,14 @@ package de.steamwar.commands.database
import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.CliktError import com.github.ajalt.clikt.core.CliktError
import com.github.ajalt.clikt.core.Context 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.flag
import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.options.option
import de.steamwar.db.Database import de.steamwar.db.Database
class DatabaseCommand: CliktCommand(name = "db") { class DatabaseCommand: CliktCommand(name = "db") {
val useProduction by option().flag() val useProduction by option().flag()
val db by requireObject<Database>() val db by findOrSetObject { Database }
override fun help(context: Context): String = "Run database commands" override fun help(context: Context): String = "Run database commands"

View File

@ -4,12 +4,14 @@ import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.requireObject import com.github.ajalt.clikt.core.requireObject
import com.github.ajalt.mordant.table.table import com.github.ajalt.mordant.table.table
import de.steamwar.db.Database import de.steamwar.db.Database
import de.steamwar.db.execute
import de.steamwar.db.useDb
class InfoCommand: CliktCommand() { class InfoCommand: CliktCommand() {
val db by requireObject<Database>() val db by requireObject<Database>()
override fun run() { override fun run() = useDb {
val tables = db.execute("SHOW TABLES") { it.getString(1) } val tables = execute("SHOW TABLES") { it.getString(1) }
echo( echo(
table { table {

View File

@ -6,12 +6,14 @@ import com.github.ajalt.clikt.core.requireObject
import com.github.ajalt.mordant.rendering.TextColors import com.github.ajalt.mordant.rendering.TextColors
import com.github.ajalt.mordant.rendering.TextStyles import com.github.ajalt.mordant.rendering.TextStyles
import de.steamwar.db.Database import de.steamwar.db.Database
import de.steamwar.db.execute
import de.steamwar.db.useDb
import java.io.File import java.io.File
class ResetCommand: CliktCommand() { class ResetCommand: CliktCommand() {
val db by requireObject<Database>() val db by requireObject<Database>()
override fun run() { override fun run() = useDb {
val schemaFile = File("/var/Schema.sql") val schemaFile = File("/var/Schema.sql")
if (!schemaFile.exists()) { if (!schemaFile.exists()) {
throw CliktError("Schema file not found!") throw CliktError("Schema file not found!")
@ -19,12 +21,12 @@ class ResetCommand: CliktCommand() {
val schema = schemaFile.readText() 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) { 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!"))) echo(TextColors.brightGreen(TextStyles.bold("Database reset!")))
} }

View File

@ -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.help
import com.github.ajalt.clikt.parameters.arguments.multiple import com.github.ajalt.clikt.parameters.arguments.multiple
import com.github.ajalt.clikt.parameters.options.default 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.flag
import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.help
import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.options.option
@ -51,15 +52,13 @@ class DevCommand : CliktCommand("dev") {
override val treatUnknownOptionsAsArgs = true override val treatUnknownOptionsAsArgs = true
val server by argument().help("Server Template") val server by argument().help("Server Template")
val port by option("--port").long().default( val port by option("--port").long().defaultLazy { UnixSystem().uid + 1010 }.help("Port for Server")
if (System.getProperty("os.name").lowercase() == "windows"
) 2050 else (UnixSystem().uid + 1010)
).help("Port for Server")
val world by option("--world", "-w").path(canBeFile = false).help("User World") 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 plugins by option("--plugins", "-p").path(true, canBeFile = false).help("Plugin Dir")
val profile by option().flag().help("Add Profiling Arguments") val profile by option().flag().help("Add Profiling Arguments")
val forceUpgrade by option().flag().help("Force Upgrade") val forceUpgrade by option().flag().help("Force Upgrade")
val jar by option().file(true, canBeDir = false).help("Jar File") 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() val jvmArgs by argument().multiple()
override val printHelpOnEmptyArgs = true override val printHelpOnEmptyArgs = true
@ -110,8 +109,7 @@ class DevCommand : CliktCommand("dev") {
try { try {
devFile.delete() devFile.delete()
} catch (_: Exception) { } catch (_: Exception) { /* ignored */ }
}
} }
} }
@ -164,8 +162,8 @@ class DevCommand : CliktCommand("dev") {
} }
fun runServer(args: List<String>, jvmArgs: List<String>, cmd: List<String>, serverDir: File) { fun runServer(args: List<String>, jvmArgs: List<String>, cmd: List<String>, serverDir: File) {
val command = arrayOf( val process = ProcessBuilder(
if (isJava8(server)) "/usr/lib/jvm/openj9-8/bin/java" else "java", jvm?.absolutePath ?: if (isJava8(server)) "/usr/lib/jvm/openj9-8/bin/java" else "java",
*jvmArgs.toTypedArray(), *jvmArgs.toTypedArray(),
*args.toTypedArray(), *args.toTypedArray(),
*jvmDefaultParams, *jvmDefaultParams,
@ -174,10 +172,6 @@ class DevCommand : CliktCommand("dev") {
"-Xshareclasses:nonfatal,name=$server", "-Xshareclasses:nonfatal,name=$server",
"-jar", "-jar",
*cmd.toTypedArray() *cmd.toTypedArray()
)
echo(command.joinToString(" "))
val process = ProcessBuilder(
*command
).directory(serverDir).inheritIO().start() ).directory(serverDir).inheritIO().start()
process.waitFor() process.waitFor()
} }

View File

@ -2,18 +2,14 @@ package de.steamwar.commands.user
import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.CliktError 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.argument
import com.github.ajalt.clikt.parameters.arguments.help import com.github.ajalt.clikt.parameters.arguments.help
import com.github.ajalt.mordant.table.table import com.github.ajalt.mordant.table.table
import de.steamwar.db.findUser import de.steamwar.db.findUser
import de.steamwar.db.schema.Session import de.steamwar.db.schema.Session
import de.steamwar.db.schema.SteamwarUser import de.steamwar.db.useDb
import de.steamwar.db.schema.SteamwarUserTable
import org.jetbrains.exposed.v1.core.eq 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.selectAll
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
import kotlin.time.DurationUnit import kotlin.time.DurationUnit
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
@ -24,8 +20,7 @@ class UserInfoCommand : CliktCommand("info") {
override val printHelpOnEmptyArgs = true override val printHelpOnEmptyArgs = true
@OptIn(ExperimentalTime::class) @OptIn(ExperimentalTime::class)
override fun run() { override fun run() = useDb {
transaction {
val sessions = val sessions =
Session.selectAll().where { Session.user eq user.id.value }.map { it[Session.start] to it[Session.end] } Session.selectAll().where { Session.user eq user.id.value }.map { it[Session.start] to it[Session.end] }
@ -63,6 +58,6 @@ class UserInfoCommand : CliktCommand("info") {
} }
} }
) )
}
} }
} }

View File

@ -9,9 +9,9 @@ import de.steamwar.db.joinedOr
import de.steamwar.db.schema.SteamwarUser import de.steamwar.db.schema.SteamwarUser
import de.steamwar.db.schema.SteamwarUserTable import de.steamwar.db.schema.SteamwarUserTable
import de.steamwar.db.schema.Team import de.steamwar.db.schema.Team
import de.steamwar.db.useDb
import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.core.like import org.jetbrains.exposed.v1.core.like
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
class UserSearchCommand : CliktCommand("search") { class UserSearchCommand : CliktCommand("search") {
val query by argument().help("Name, Id, UUID or DiscordId") 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 help(context: Context): String = "Search for users"
override fun run() = transaction { override fun run() = useDb {
val users = SteamwarUser.find { val users = SteamwarUser.find {
joinedOr( joinedOr(
SteamwarUserTable.username like "%$query%", SteamwarUserTable.username like "%$query%",

View File

@ -5,32 +5,26 @@ import com.github.ajalt.clikt.core.CliktError
import de.steamwar.db.schema.SteamwarUser import de.steamwar.db.schema.SteamwarUser
import de.steamwar.db.schema.SteamwarUserTable import de.steamwar.db.schema.SteamwarUserTable
import org.jetbrains.exposed.v1.core.Expression 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.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.eq
import org.jetbrains.exposed.v1.core.or import org.jetbrains.exposed.v1.core.or
import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.v1.jdbc.Database
import org.jetbrains.exposed.v1.jdbc.JdbcTransaction
import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.transactions.transaction
import java.io.File import java.io.File
import java.sql.ResultSet import java.sql.ResultSet
import java.util.Properties import java.util.Properties
import java.util.UUID
import kotlin.time.ExperimentalTime
import kotlin.time.Instant
class Database { object Database {
val host: String lateinit var host: String
val port: String lateinit var port: String
val database: 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") val config = File(System.getProperty("user.home"), "mysql.properties")
if (!config.exists()) { if (!config.exists()) {
@ -50,26 +44,8 @@ class Database {
val url = "jdbc:mariadb://$host:$port/$database" val url = "jdbc:mariadb://$host:$port/$database"
Database.Companion.connect(url, driver = "org.mariadb.jdbc.Driver", user = username, password = password) db = Database.connect(url, driver = "org.mariadb.jdbc.Driver", user = username, password = password)
} return
fun <T> execute(sql: String, transform: (ResultSet) -> T): List<T> = transaction {
val result = mutableListOf<T>()
exec(sql) { rs ->
while (rs.next()) {
result += transform(rs)
}
}
return@transaction result
}
fun <T> executeSingle(sql: String, transform: (ResultSet) -> T): T? {
return execute(sql) { rs ->
if (!rs.next()) {
return@execute null
}
transform(rs)
}.single()
} }
} }
@ -81,3 +57,28 @@ fun <T: BaseCliktCommand<T>> BaseCliktCommand<T>.findUser(query: String): Steamw
fun joinedOr(vararg expressions: Expression<Boolean>?): Op<Boolean> = fun joinedOr(vararg expressions: Expression<Boolean>?): Op<Boolean> =
expressions.filterNotNull().reduce { acc, expression -> acc or expression } as Op<Boolean> expressions.filterNotNull().reduce { acc, expression -> acc or expression } as Op<Boolean>
fun <T> JdbcTransaction.execute(sql: String, transform: (ResultSet) -> T): List<T> {
val result = mutableListOf<T>()
exec(sql) { rs ->
while (rs.next()) {
result += transform(rs)
}
}
return result
}
fun <T> 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)
}