forked from SteamWar/SteamWar
197 lines
5.3 KiB
Kotlin
197 lines
5.3 KiB
Kotlin
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 <T : BaseCliktCommand<T>> BaseCliktCommand<T>.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<Boolean>?): 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 JdbcTransaction.executeScript(sql: String) {
|
|
for (statement in splitSqlScript(sql)) {
|
|
exec(statement) { }
|
|
}
|
|
}
|
|
|
|
private fun splitSqlScript(sql: String): List<String> {
|
|
val statements = mutableListOf<String>()
|
|
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)
|
|
}
|