package de.steamwar.db import com.github.ajalt.clikt.core.BaseCliktCommand import com.github.ajalt.clikt.core.CliktError import de.steamwar.sql.SteamwarUser import de.steamwar.sql.SteamwarUserTable import org.jetbrains.exposed.v1.core.Expression import org.jetbrains.exposed.v1.core.Op 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.* object Database { val host: String val port: String val database: String val username: String val password: String lateinit var db: Database init { val config = File(System.getProperty("user.home"), "mysql.properties") if (!config.exists()) { throw CliktError("Config file not found!") } val props = Properties(); props.load(config.inputStream()) host = props.getProperty("host") port = props.getProperty("port") database = props.getProperty("database") username = props.getProperty("user") password = props.getProperty("password") } fun ensureConnected() { if (::db.isInitialized) { return } val url = "jdbc:mariadb://$host:$port/$database" db = Database.connect(url, driver = "org.mariadb.jdbc.Driver", user = username, password = password) return } } fun > BaseCliktCommand.findUser(query: String): SteamwarUser? = transaction { SteamwarUser.find { joinedOr(query.toIntOrNull()?.let { SteamwarUserTable.id eq it }, (SteamwarUserTable.username eq query), SteamwarUserTable.uuid eq query, query.toLongOrNull()?.let { SteamwarUserTable.discordId eq it }) } .firstOrNull() ?.let { return@transaction it } } fun joinedOr(vararg expressions: Expression?): Op = 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 JdbcTransaction.executeScript(sql: String) { for (statement in splitSqlScript(sql)) { exec(statement) { } } } private fun splitSqlScript(sql: String): List { val statements = mutableListOf() val current = StringBuilder() var quote: Char? = null var inLineComment = false var inBlockComment = false var index = 0 fun addStatement() { val statement = current.toString().trim() if (statement.isNotEmpty()) { statements += statement } current.clear() } while (index < sql.length) { val char = sql[index] val next = sql.getOrNull(index + 1) if (inLineComment) { current.append(char) if (char == '\n') { inLineComment = false } index++ continue } if (inBlockComment) { current.append(char) if (char == '*' && next == '/') { current.append(next) inBlockComment = false index += 2 } else { index++ } continue } if (quote != null) { current.append(char) if (char == '\\' && quote != '`' && next != null) { current.append(next) index += 2 continue } if (char == quote) { if (next == quote) { current.append(next) index += 2 continue } quote = null } index++ continue } when { char == '-' && next == '-' -> { current.append(char).append(next) inLineComment = true index += 2 } char == '#' -> { current.append(char) inLineComment = true index++ } char == '/' && next == '*' -> { current.append(char).append(next) inBlockComment = true index += 2 } char == '\'' || char == '"' || char == '`' -> { current.append(char) quote = char index++ } char == ';' -> { addStatement() index++ } else -> { current.append(char) index++ } } } addStatement() return statements } fun useDb(statement: JdbcTransaction.() -> Unit) { de.steamwar.db.Database.ensureConnected() transaction(de.steamwar.db.Database.db, statement = statement) }