Skip to content
This repository was archived by the owner on Dec 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ class CharUuidColumnType : ColumnType<UUID>() {
@Language("SQL")
override fun sqlType(): String = "CHAR(36)"

override fun valueFromDB(value: Any): UUID? = when {
value is UUID -> value
value is ByteArray -> ByteBuffer.wrap(value).let { UUID(it.long, it.long) }
value is String && value.matches(uuidRegexp) -> UUID.fromString(value)
value is String -> ByteBuffer.wrap(value.toByteArray()).let { UUID(it.long, it.long) }
override fun valueFromDB(value: Any): UUID? = when (value) {
is UUID -> value
is ByteArray -> ByteBuffer.wrap(value).let { UUID(it.long, it.long) }
is String if value.matches(uuidRegexp) -> UUID.fromString(value)
is String -> ByteBuffer.wrap(value.toByteArray()).let { UUID(it.long, it.long) }
is ByteBuffer -> UUID(value.long, value.long)
else -> error("Unexpected value of type UUID: $value of ${value::class.qualifiedName}")
}

override fun notNullValueToDB(value: UUID): Any = value.toString()
override fun nonNullValueToString(value: UUID): String = "'$value'"

companion object {
private val uuidRegexp =
internal val uuidRegexp =
Regex(
"[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}",
RegexOption.IGNORE_CASE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.slne.surf.cloud.api.server.exposed.columns

import org.intellij.lang.annotations.Language
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.ColumnType
import org.jetbrains.exposed.sql.Table
import java.nio.ByteBuffer
import java.util.*

class NativeUuidColumnType : ColumnType<UUID>() {
@Language("SQL")
override fun sqlType() = "UUID"

override fun valueFromDB(value: Any): UUID? = when (value) {
is UUID -> value
is String if value.matches(CharUuidColumnType.uuidRegexp) -> UUID.fromString(value)
is String -> ByteBuffer.wrap(value.toByteArray()).let { UUID(it.long, it.long) }
is ByteArray -> ByteBuffer.wrap(value).let { UUID(it.long, it.long) }
is ByteBuffer -> UUID(value.long, value.long)
else -> error("Unexpected value of type UUID: $value of ${value::class.qualifiedName}")
}
}

fun Table.nativeUuid(name: String): Column<UUID> =
registerColumn(name, NativeUuidColumnType())
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,7 @@ package dev.slne.surf.cloud.standalone

import MigrationUtils
import dev.slne.surf.cloud.api.common.config.properties.requiredSystemProperty
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.BanPunishmentIpAddressTable
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.BanPunishmentNoteTable
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.BanPunishmentTable
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.KickPunishmentNoteTable
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.KickPunishmentTable
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.MutePunishmentNoteTable
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.MutePunishmentTable
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.WarnPunishmentNoteTable
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.WarnPunishmentTable
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.*
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.ExperimentalDatabaseMigrationApi
import org.jetbrains.exposed.sql.transactions.transaction
Expand All @@ -35,7 +27,7 @@ fun main() {
MutePunishmentNoteTable,
WarnPunishmentNoteTable,
scriptDirectory = "src/main/resources/db/migration",
scriptName = "V4__add_punishment_table_indexes",
scriptName = "V5__replace_string_uuid_with_native_uuid",
)
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package dev.slne.surf.cloud.standalone.player.db.exposed

import dev.slne.surf.cloud.api.server.exposed.columns.charUuid
import dev.slne.surf.cloud.api.server.exposed.columns.inet
import dev.slne.surf.cloud.api.server.exposed.columns.nativeUuid
import dev.slne.surf.cloud.api.server.exposed.columns.zonedDateTime
import dev.slne.surf.cloud.api.server.exposed.table.AuditableLongIdTable
import java.net.Inet4Address

object CloudPlayerTable : AuditableLongIdTable("cloud_player") {
val uuid = charUuid("uuid").uniqueIndex()
val uuid = nativeUuid("uuid").uniqueIndex()
val lastServer = char("last_server", 255).nullable()
val lastSeen = zonedDateTime("last_seen").nullable()
val lastIpAddress = inet("last_ip_address")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table

import dev.slne.surf.cloud.api.server.exposed.columns.charUuid
import dev.slne.surf.cloud.api.server.exposed.columns.nativeUuid
import dev.slne.surf.cloud.api.server.exposed.table.AuditableLongIdTable

abstract class AbstractPunishmentTable(name: String): AuditableLongIdTable(name) {
abstract class AbstractPunishmentTable(name: String) : AuditableLongIdTable(name) {
val punishmentId = char("punishment_id", 8).uniqueIndex()
val punishedUuid = charUuid("punished_uuid")
val issuerUuid = charUuid("issuer_uuid").nullable()
val punishedUuid = nativeUuid("punished_uuid")
val issuerUuid = nativeUuid("issuer_uuid").nullable()
val reason = largeText("reason").nullable()

init {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table

import dev.slne.surf.cloud.api.server.exposed.columns.charUuid
import dev.slne.surf.cloud.api.server.exposed.columns.nativeUuid
import dev.slne.surf.cloud.api.server.exposed.columns.zonedDateTime

abstract class AbstractUnpunishableExpirablePunishmentTable(name: String) : AbstractPunishmentTable(name) {
abstract class AbstractUnpunishableExpirablePunishmentTable(name: String) :
AbstractPunishmentTable(name) {
val unpunished = bool("unpunished").default(false)
val unpunishedDate = zonedDateTime("unpunished_date").nullable().default(null)
val unpunisherUuid = charUuid("unpunisher_uuid").nullable().default(null)
val unpunisherUuid = nativeUuid("unpunisher_uuid").nullable().default(null)
val expirationDate = zonedDateTime("expiration_date").nullable().default(null)
val permanent = bool("permanent").default(false)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table

import dev.slne.surf.cloud.api.server.exposed.columns.charUuid
import dev.slne.surf.cloud.api.server.exposed.columns.nativeUuid
import dev.slne.surf.cloud.api.server.exposed.table.AuditableLongIdTable
import org.jetbrains.exposed.sql.ReferenceOption
import java.util.*
Expand All @@ -9,7 +9,7 @@ abstract class AbstractPunishmentNoteTable(
name: String,
foreignPunishmentTable: AbstractPunishmentTable
) : AuditableLongIdTable(name) {
val noteId = charUuid("note_id").uniqueIndex().clientDefault { UUID.randomUUID() }
val noteId = nativeUuid("note_id").uniqueIndex().clientDefault { UUID.randomUUID() }
val punishment =
reference("punishment_id", foreignPunishmentTable, onDelete = ReferenceOption.CASCADE)
val note = largeText("note")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
-- V5__replace_string_uuid_with_native_uuid.sql
-- Migration to replace CHAR(36) UUID columns with native UUID types
-- Assumes data is UUID-valid and castable

-- Convert `cloud_player`.`uuid`
ALTER TABLE cloud_player
MODIFY COLUMN uuid UUID NOT NULL;

-- Convert `punish_bans` UUID columns
ALTER TABLE punish_bans
MODIFY COLUMN punished_uuid UUID NOT NULL,
MODIFY COLUMN issuer_uuid UUID NULL,
MODIFY COLUMN unpunisher_uuid UUID NULL;

-- Convert `punish_kicks` UUID columns
ALTER TABLE punish_kicks
MODIFY COLUMN punished_uuid UUID NOT NULL,
MODIFY COLUMN issuer_uuid UUID NULL;

-- Convert `punish_mutes` UUID columns
ALTER TABLE punish_mutes
MODIFY COLUMN punished_uuid UUID NOT NULL,
MODIFY COLUMN issuer_uuid UUID NULL,
MODIFY COLUMN unpunisher_uuid UUID NULL;

-- Convert `punish_notes_ban`.`note_id`
ALTER TABLE punish_notes_ban
MODIFY COLUMN note_id UUID NOT NULL;

-- Convert `punish_notes_kick`.`note_id`
ALTER TABLE punish_notes_kick
MODIFY COLUMN note_id UUID NOT NULL;

-- Convert `punish_notes_mute`.`note_id`
ALTER TABLE punish_notes_mute
MODIFY COLUMN note_id UUID NOT NULL;

-- Convert `punish_notes_warn`.`note_id`
ALTER TABLE punish_notes_warn
MODIFY COLUMN note_id UUID NOT NULL;

-- Convert `punish_warnings` UUID columns
ALTER TABLE punish_warnings
MODIFY COLUMN punished_uuid UUID NOT NULL,
MODIFY COLUMN issuer_uuid UUID NULL;