Skip to content

Commit dcfba5f

Browse files
authored
Migrated to Kotlin Serialization (#135)
Signed-off-by: Arnau Mora <[email protected]> Signed-off-by: Arnau Mora Gras <[email protected]>
1 parent 55a27aa commit dcfba5f

File tree

117 files changed

+1949
-2527
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+1949
-2527
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ bin/
4444

4545
### Ignore testing database ###
4646
testing.db
47+
testing.db-journal
4748

4849
### Ignore secrets file ###
4950
local.properties

build.gradle.kts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import io.ktor.plugin.features.DockerPortMappingProtocol
44

55
plugins {
66
alias(libs.plugins.kotlin.jvm)
7-
alias(libs.plugins.ktor)
7+
alias(libs.plugins.kotlin.serialization)
88
alias(libs.plugins.kotlinx.kover)
9+
alias(libs.plugins.ktor)
910
alias(libs.plugins.sentry)
1011
}
1112

@@ -29,10 +30,8 @@ val tcnativeClassifier = when {
2930
}
3031

3132
dependencies {
32-
// JSON support
33-
implementation(libs.json)
34-
3533
// Ktor dependencies
34+
implementation(libs.ktor.server.contentNegotiation)
3635
implementation(libs.ktor.server.core)
3736
implementation(libs.ktor.server.netty)
3837
implementation(libs.ktor.server.locations)
@@ -41,14 +40,20 @@ dependencies {
4140
implementation(libs.ktor.utils)
4241

4342
// Ktor client for making requests
43+
implementation(libs.ktor.client.contentNegotiation)
4444
implementation(libs.ktor.client.core)
4545
implementation(libs.ktor.client.cio)
4646

47+
// Kotlin Serialization & Ktor Serialization
48+
implementation(libs.kotlin.serializationJson)
49+
implementation(libs.ktor.serializationJson)
50+
4751
// Exposed dependencies
4852
implementation(libs.exposed.core)
4953
implementation(libs.exposed.dao)
5054
implementation(libs.exposed.jdbc)
5155
implementation(libs.exposed.javaTime)
56+
implementation(libs.exposed.json)
5257

5358
// Database engines
5459
implementation(libs.postgresql)

gradle/libs.versions.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ exposed = "0.51.1"
44
firebase-admin = "9.3.0"
55
foojay-resolver = "0.8.0"
66
imageio-webp = "0.1.6"
7-
json = "20240303"
87
kotlin = "2.0.0"
98
kotlinx-kover = "0.8.0"
9+
kotlin-serialization = "1.6.3"
1010
ktor = "2.3.11"
1111
postgresql = "42.7.3"
1212
progressbar = "0.10.1"
@@ -17,10 +17,13 @@ sqlite = "3.46.0.0"
1717
crowdin = { module = "com.github.crowdin:crowdin-api-client-java", version.ref = "crowdin" }
1818
firebase-admin = { module = "com.google.firebase:firebase-admin", version.ref = "firebase-admin" }
1919
imageio-webp = { module = "org.sejda.imageio:webp-imageio", version.ref = "imageio-webp" }
20-
json = { module = "org.json:json", version.ref = "json" }
20+
kotlin-serializationJson = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlin-serialization" }
2121
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
22+
ktor-client-contentNegotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
2223
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
2324
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
25+
ktor-serializationJson = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
26+
ktor-server-contentNegotiation = { module = "io.ktor:ktor-server-content-negotiation", version.ref = "ktor" }
2427
ktor-server-core = { module = "io.ktor:ktor-server-core", version.ref = "ktor" }
2528
ktor-server-netty = { module = "io.ktor:ktor-server-netty", version.ref = "ktor" }
2629
ktor-server-locations = { module = "io.ktor:ktor-server-locations", version.ref = "ktor" }
@@ -32,13 +35,14 @@ exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "e
3235
exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" }
3336
exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" }
3437
exposed-javaTime = { module = "org.jetbrains.exposed:exposed-java-time", version.ref = "exposed" }
38+
exposed-json = { module = "org.jetbrains.exposed:exposed-json", version.ref = "exposed" }
3539
postgresql = { module = "org.postgresql:postgresql", version.ref = "postgresql" }
3640
progressbar = { module = "me.tongfei:progressbar", version.ref = "progressbar" }
3741
sqlite = { module = "org.xerial:sqlite-jdbc", version.ref = "sqlite" }
3842

3943
[plugins]
40-
gradle-toolchains-fooljayResolver = { id = "org.gradle.toolchains.foojay-resolver-convention", version.ref = "foojay-resolver" }
4144
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
45+
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
4246
kotlinx-kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kotlinx-kover" }
4347
ktor = { id = "io.ktor.plugin", version.ref = "ktor" }
4448
sentry = { id = "io.sentry.jvm.gradle", version.ref = "sentry" }

src/main/kotlin/Main.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fun main() {
2828
ServerDatabase.configureFromEnvironment()
2929

3030
Logger.info("Connecting to the database, and creating tables...")
31-
ServerDatabase.instance.initialize()
31+
runBlocking { ServerDatabase.instance.initialize() }
3232

3333
Logger.info("Initializing Crowdin connection...")
3434
Localization.init()

src/main/kotlin/ServerDatabase.kt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import database.entity.info.Version
2+
import database.migration.Migration
13
import database.table.Areas
24
import database.table.BlockingTable
35
import database.table.InfoTable
@@ -46,6 +48,8 @@ class ServerDatabase private constructor() {
4648
*/
4749
val instance by lazy { ServerDatabase() }
4850

51+
const val VERSION = 1
52+
4953
/**
5054
* Configures the database connection parameters from the environment variables.
5155
*
@@ -78,13 +82,36 @@ class ServerDatabase private constructor() {
7882
* Creates all the missing tables and columns for the database.
7983
* Should be run as soon as possible in the program's lifecycle.
8084
*/
81-
fun initialize() = transaction(database) {
85+
suspend fun initialize() = invoke {
8286
SchemaUtils.createMissingTablesAndColumns(Areas, Zones, Sectors, Paths, BlockingTable, InfoTable)
87+
88+
var loops = 0
89+
while (Version.updateRequired()) {
90+
check(loops++ <= VERSION) { "Version update loop detected" }
91+
val version = Version.get()
92+
val migration = Migration.all.find { it.from == version }
93+
?: error("No migration found for version $version")
94+
Logger.info("Migrating database from version $version to ${migration.to}")
95+
with(migration) { this@invoke() }
96+
}
8397
}
8498

99+
suspend operator fun <T> invoke(block: suspend Transaction.() -> T): T = query(block)
100+
85101
suspend fun <T> query(block: suspend Transaction.() -> T): T = newSuspendedTransaction(Dispatchers.IO, database) {
86102
logger?.let { addLogger(it) }
87103

88104
block()
89105
}
106+
107+
/**
108+
* Begins a transaction and runs the given block of code in it.
109+
*
110+
* @param block The block of code to run in the transaction.
111+
*/
112+
fun <T> querySync(block: Transaction.() -> T) = transaction(database) {
113+
logger?.let { addLogger(it) }
114+
115+
block()
116+
}
90117
}

src/main/kotlin/data/BlockingRecurrenceYearly.kt

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,15 @@
11
package data
22

33
import java.time.Month
4-
import org.json.JSONObject
5-
import utils.getUShort
6-
import utils.jsonOf
7-
import utils.serialization.JsonSerializable
8-
import utils.serialization.JsonSerializer
4+
import kotlinx.serialization.Serializable
95

6+
@Serializable
107
data class BlockingRecurrenceYearly(
118
val fromDay: UShort,
129
val fromMonth: Month,
1310
val toDay: UShort,
1411
val toMonth: Month
15-
): JsonSerializable {
16-
companion object: JsonSerializer<BlockingRecurrenceYearly> {
17-
override fun fromJson(json: JSONObject): BlockingRecurrenceYearly = BlockingRecurrenceYearly(
18-
json.getUShort("from_day"),
19-
json.getEnum(Month::class.java, "from_month"),
20-
json.getUShort("to_day"),
21-
json.getEnum(Month::class.java, "to_month")
22-
)
23-
}
24-
25-
override fun toJson(): JSONObject = jsonOf(
26-
"from_day" to fromDay,
27-
"from_month" to fromMonth,
28-
"to_day" to toDay,
29-
"to_month" to toMonth
30-
)
31-
12+
) {
3213
override fun equals(other: Any?): Boolean {
3314
if (this === other) return true
3415
if (javaClass != other?.javaClass) return false
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package data
22

33
import KoverIgnore
4+
import kotlinx.serialization.Serializable
45

56
@KoverIgnore
7+
@Serializable
68
enum class BlockingTypes {
79
DRY, BUILD, BIRD, OLD, PLANTS, ROPE_LENGTH
810
}

src/main/kotlin/data/Builder.kt

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,9 @@
11
package data
22

3-
import org.json.JSONObject
4-
import utils.getStringOrNull
5-
import utils.jsonOf
6-
import utils.serialization.JsonSerializable
7-
import utils.serialization.JsonSerializer
3+
import kotlinx.serialization.Serializable
84

5+
@Serializable
96
data class Builder(
107
val name: String?,
118
val date: String?
12-
): JsonSerializable {
13-
companion object: JsonSerializer<Builder> {
14-
override fun fromJson(json: JSONObject): Builder = Builder(
15-
json.getStringOrNull("name"),
16-
json.getStringOrNull("date")
17-
)
18-
}
19-
20-
override fun toJson(): JSONObject = jsonOf("name" to name, "date" to date)
21-
}
9+
)

src/main/kotlin/data/DataPoint.kt

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package data
22

3-
import org.json.JSONObject
4-
import utils.jsonOf
5-
import utils.serialization.JsonSerializable
6-
import utils.serialization.JsonSerializer
3+
import kotlinx.serialization.Serializable
74

85
/**
96
* Represents a data point with location, label, and icon information.
@@ -12,22 +9,9 @@ import utils.serialization.JsonSerializer
129
* @property label The label associated with the data point.
1310
* @property icon The icon associated with the data point.
1411
*/
12+
@Serializable
1513
data class DataPoint(
1614
val location: LatLng,
1715
val label: String,
1816
val icon: String
19-
): JsonSerializable {
20-
companion object: JsonSerializer<DataPoint> {
21-
override fun fromJson(json: JSONObject): DataPoint = DataPoint(
22-
LatLng.fromJson(json.getJSONObject("location")),
23-
json.getString("label"),
24-
json.getString("icon")
25-
)
26-
}
27-
28-
override fun toJson(): JSONObject = jsonOf(
29-
"location" to location,
30-
"label" to label,
31-
"icon" to icon
32-
)
33-
}
17+
)

src/main/kotlin/data/Ending.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package data
22

33
import KoverIgnore
4+
import kotlinx.serialization.Serializable
45

56
@KoverIgnore
7+
@Serializable
68
enum class Ending {
79
NONE,
810
PLATE,

0 commit comments

Comments
 (0)