Skip to content
This repository was archived by the owner on Dec 10, 2025. It is now read-only.

Commit ce03675

Browse files
committed
refactor(database): replace charUuid with nativeUuid and update schema to use native UUID column types
1 parent 83a271a commit ce03675

File tree

8 files changed

+91
-27
lines changed

8 files changed

+91
-27
lines changed

surf-cloud-api/surf-cloud-api-server/src/main/kotlin/dev/slne/surf/cloud/api/server/exposed/columns/CharUuidColumnType.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,20 @@ class CharUuidColumnType : ColumnType<UUID>() {
1111
@Language("SQL")
1212
override fun sqlType(): String = "CHAR(36)"
1313

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

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

2526
companion object {
26-
private val uuidRegexp =
27+
internal val uuidRegexp =
2728
Regex(
2829
"[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}",
2930
RegexOption.IGNORE_CASE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package dev.slne.surf.cloud.api.server.exposed.columns
2+
3+
import org.intellij.lang.annotations.Language
4+
import org.jetbrains.exposed.sql.Column
5+
import org.jetbrains.exposed.sql.ColumnType
6+
import org.jetbrains.exposed.sql.Table
7+
import java.nio.ByteBuffer
8+
import java.util.*
9+
10+
class NativeUuidColumnType : ColumnType<UUID>() {
11+
@Language("SQL")
12+
override fun sqlType() = "UUID()"
13+
14+
override fun valueFromDB(value: Any): UUID? = when (value) {
15+
is UUID -> value
16+
is String if value.matches(CharUuidColumnType.uuidRegexp) -> UUID.fromString(value)
17+
is String -> ByteBuffer.wrap(value.toByteArray()).let { UUID(it.long, it.long) }
18+
is ByteArray -> ByteBuffer.wrap(value).let { UUID(it.long, it.long) }
19+
is ByteBuffer -> UUID(value.long, value.long)
20+
else -> error("Unexpected value of type UUID: $value of ${value::class.qualifiedName}")
21+
}
22+
}
23+
24+
fun Table.nativeUuid(name: String): Column<UUID> =
25+
registerColumn(name, NativeUuidColumnType())

surf-cloud-standalone/src/main/kotlin/dev/slne/surf/cloud/standalone/GenerateExposedMigrationScript.kt

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,7 @@ package dev.slne.surf.cloud.standalone
22

33
import MigrationUtils
44
import dev.slne.surf.cloud.api.common.config.properties.requiredSystemProperty
5-
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.BanPunishmentIpAddressTable
6-
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.BanPunishmentNoteTable
7-
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.BanPunishmentTable
8-
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.KickPunishmentNoteTable
9-
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.KickPunishmentTable
10-
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.MutePunishmentNoteTable
11-
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.MutePunishmentTable
12-
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.WarnPunishmentNoteTable
13-
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.WarnPunishmentTable
5+
import dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table.*
146
import org.jetbrains.exposed.sql.Database
157
import org.jetbrains.exposed.sql.ExperimentalDatabaseMigrationApi
168
import org.jetbrains.exposed.sql.transactions.transaction
@@ -35,7 +27,7 @@ fun main() {
3527
MutePunishmentNoteTable,
3628
WarnPunishmentNoteTable,
3729
scriptDirectory = "src/main/resources/db/migration",
38-
scriptName = "V4__add_punishment_table_indexes",
30+
scriptName = "V5__replace_string_uuid_with_native_uuid",
3931
)
4032
}
4133
}

surf-cloud-standalone/src/main/kotlin/dev/slne/surf/cloud/standalone/player/db/exposed/CloudPlayerTables.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package dev.slne.surf.cloud.standalone.player.db.exposed
22

3-
import dev.slne.surf.cloud.api.server.exposed.columns.charUuid
43
import dev.slne.surf.cloud.api.server.exposed.columns.inet
4+
import dev.slne.surf.cloud.api.server.exposed.columns.nativeUuid
55
import dev.slne.surf.cloud.api.server.exposed.columns.zonedDateTime
66
import dev.slne.surf.cloud.api.server.exposed.table.AuditableLongIdTable
77
import java.net.Inet4Address
88

99
object CloudPlayerTable : AuditableLongIdTable("cloud_player") {
10-
val uuid = charUuid("uuid").uniqueIndex()
10+
val uuid = nativeUuid("uuid").uniqueIndex()
1111
val lastServer = char("last_server", 255).nullable()
1212
val lastSeen = zonedDateTime("last_seen").nullable()
1313
val lastIpAddress = inet("last_ip_address")

surf-cloud-standalone/src/main/kotlin/dev/slne/surf/cloud/standalone/player/db/exposed/punishment/table/AbstractPunishmentTable.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table
22

3-
import dev.slne.surf.cloud.api.server.exposed.columns.charUuid
3+
import dev.slne.surf.cloud.api.server.exposed.columns.nativeUuid
44
import dev.slne.surf.cloud.api.server.exposed.table.AuditableLongIdTable
55

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

1212
init {

surf-cloud-standalone/src/main/kotlin/dev/slne/surf/cloud/standalone/player/db/exposed/punishment/table/AbstractUnpunishableExpirablePunishmentTable.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table
22

3-
import dev.slne.surf.cloud.api.server.exposed.columns.charUuid
3+
import dev.slne.surf.cloud.api.server.exposed.columns.nativeUuid
44
import dev.slne.surf.cloud.api.server.exposed.columns.zonedDateTime
55

6-
abstract class AbstractUnpunishableExpirablePunishmentTable(name: String) : AbstractPunishmentTable(name) {
6+
abstract class AbstractUnpunishableExpirablePunishmentTable(name: String) :
7+
AbstractPunishmentTable(name) {
78
val unpunished = bool("unpunished").default(false)
89
val unpunishedDate = zonedDateTime("unpunished_date").nullable().default(null)
9-
val unpunisherUuid = charUuid("unpunisher_uuid").nullable().default(null)
10+
val unpunisherUuid = nativeUuid("unpunisher_uuid").nullable().default(null)
1011
val expirationDate = zonedDateTime("expiration_date").nullable().default(null)
1112
val permanent = bool("permanent").default(false)
1213

surf-cloud-standalone/src/main/kotlin/dev/slne/surf/cloud/standalone/player/db/exposed/punishment/table/PunishmentNoteTables.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package dev.slne.surf.cloud.standalone.player.db.exposed.punishment.table
22

3-
import dev.slne.surf.cloud.api.server.exposed.columns.charUuid
3+
import dev.slne.surf.cloud.api.server.exposed.columns.nativeUuid
44
import dev.slne.surf.cloud.api.server.exposed.table.AuditableLongIdTable
55
import org.jetbrains.exposed.sql.ReferenceOption
66
import java.util.*
@@ -9,7 +9,7 @@ abstract class AbstractPunishmentNoteTable(
99
name: String,
1010
foreignPunishmentTable: AbstractPunishmentTable
1111
) : AuditableLongIdTable(name) {
12-
val noteId = charUuid("note_id").uniqueIndex().clientDefault { UUID.randomUUID() }
12+
val noteId = nativeUuid("note_id").uniqueIndex().clientDefault { UUID.randomUUID() }
1313
val punishment =
1414
reference("punishment_id", foreignPunishmentTable, onDelete = ReferenceOption.CASCADE)
1515
val note = largeText("note")
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
-- V5__replace_string_uuid_with_native_uuid.sql
2+
-- Migration to replace CHAR(36) UUID columns with native UUID types
3+
-- Assumes data is UUID-valid and castable
4+
5+
-- Convert `cloud_player`.`uuid`
6+
ALTER TABLE cloud_player
7+
MODIFY COLUMN uuid UUID NOT NULL;
8+
9+
-- Convert `punish_bans` UUID columns
10+
ALTER TABLE punish_bans
11+
MODIFY COLUMN punished_uuid UUID NOT NULL,
12+
MODIFY COLUMN issuer_uuid UUID NULL,
13+
MODIFY COLUMN unpunisher_uuid UUID NULL;
14+
15+
-- Convert `punish_kicks` UUID columns
16+
ALTER TABLE punish_kicks
17+
MODIFY COLUMN punished_uuid UUID NOT NULL,
18+
MODIFY COLUMN issuer_uuid UUID NULL;
19+
20+
-- Convert `punish_mutes` UUID columns
21+
ALTER TABLE punish_mutes
22+
MODIFY COLUMN punished_uuid UUID NOT NULL,
23+
MODIFY COLUMN issuer_uuid UUID NULL,
24+
MODIFY COLUMN unpunisher_uuid UUID NULL;
25+
26+
-- Convert `punish_notes_ban`.`note_id`
27+
ALTER TABLE punish_notes_ban
28+
MODIFY COLUMN note_id UUID NOT NULL;
29+
30+
-- Convert `punish_notes_kick`.`note_id`
31+
ALTER TABLE punish_notes_kick
32+
MODIFY COLUMN note_id UUID NOT NULL;
33+
34+
-- Convert `punish_notes_mute`.`note_id`
35+
ALTER TABLE punish_notes_mute
36+
MODIFY COLUMN note_id UUID NOT NULL;
37+
38+
-- Convert `punish_notes_warn`.`note_id`
39+
ALTER TABLE punish_notes_warn
40+
MODIFY COLUMN note_id UUID NOT NULL;
41+
42+
-- Convert `punish_warnings` UUID columns
43+
ALTER TABLE punish_warnings
44+
MODIFY COLUMN punished_uuid UUID NOT NULL,
45+
MODIFY COLUMN issuer_uuid UUID NULL;

0 commit comments

Comments
 (0)