From 256939e62f91d8b6814bccd8801b7f00b3ce95bb Mon Sep 17 00:00:00 2001 From: MineKing <69981672+MineKing9534@users.noreply.github.com> Date: Sat, 26 Oct 2024 22:24:41 +0200 Subject: [PATCH] Add more data types (#8) * Add more data types * Adjust tests * Add minecraft color test * Add missing tests * Organize imports --- .../main/kotlin/de/mineking/database/Nodes.kt | 1 - .../de/mineking/database/DiscordMappers.kt | 21 ++++++-- .../de/mineking/database/MinecraftMappers.kt | 20 ++++++-- .../src/test/kotlin/tests/minecraft/Color.kt | 50 +++++++++++++++++++ .../test/kotlin/tests/minecraft/Location.kt | 2 +- .../src/test/kotlin/tests/minecraft/Player.kt | 2 +- .../database/vendors/postgres/Conditions.kt | 5 +- .../vendors/postgres/PostgresTypes.kt | 4 ++ .../kotlin/tests/postgres/specific/Color.kt | 32 ++++++++++++ .../kotlin/tests/postgres/specific/Locale.kt | 32 ++++++++++++ .../database/vendors/sqlite/SQLiteTypes.kt | 6 +++ .../kotlin/tests/sqlite/specific/Color.kt | 32 ++++++++++++ .../kotlin/tests/sqlite/specific/Locale.kt | 32 ++++++++++++ 13 files changed, 227 insertions(+), 12 deletions(-) create mode 100644 minecraft/src/test/kotlin/tests/minecraft/Color.kt create mode 100644 postgres/src/test/kotlin/tests/postgres/specific/Color.kt create mode 100644 postgres/src/test/kotlin/tests/postgres/specific/Locale.kt create mode 100644 sqlite/src/test/kotlin/tests/sqlite/specific/Color.kt create mode 100644 sqlite/src/test/kotlin/tests/sqlite/specific/Locale.kt diff --git a/core/src/main/kotlin/de/mineking/database/Nodes.kt b/core/src/main/kotlin/de/mineking/database/Nodes.kt index ac001e1..f5f4f75 100644 --- a/core/src/main/kotlin/de/mineking/database/Nodes.kt +++ b/core/src/main/kotlin/de/mineking/database/Nodes.kt @@ -1,7 +1,6 @@ package de.mineking.database import org.jdbi.v3.core.argument.Argument -import javax.swing.text.html.StyleSheet.BoxPainter import kotlin.reflect.KType import kotlin.reflect.full.isSubtypeOf import kotlin.reflect.jvm.jvmErasure diff --git a/discord/src/main/kotlin/de/mineking/database/DiscordMappers.kt b/discord/src/main/kotlin/de/mineking/database/DiscordMappers.kt index b5104e7..1f187d9 100644 --- a/discord/src/main/kotlin/de/mineking/database/DiscordMappers.kt +++ b/discord/src/main/kotlin/de/mineking/database/DiscordMappers.kt @@ -24,7 +24,13 @@ enum class SnowflakeType(val getter: (JDA, Long) -> ISnowflake?) { } } -internal inline fun DatabaseConnection.registerDiscordMappers(bot: JDA, mapper: TypeMapper, enumMapper: TypeMapper?, *>?, crossinline converter: (T) -> Long, crossinline extractor: (ISnowflake?) -> T?) { +internal inline fun DatabaseConnection.registerDiscordMappers( + bot: JDA, + enumMapper: TypeMapper?, *>? = null, + mapper: TypeMapper, + crossinline converter: (T) -> Long, + crossinline extractor: (ISnowflake?) -> T? +) { data["bot"] = bot if (enumMapper != null) { @@ -67,5 +73,14 @@ internal inline fun DatabaseConnection.registerDiscordMappers(bot: J typeMappers += typeMapper(mapper, { it?.let { bot.getUserById(converter(it)) } }, extractor) } -fun DatabaseConnection.registerDiscordLongMappers(bot: JDA, longType: TypeMapper, enumType: TypeMapper?, *>? = null) = registerDiscordMappers(bot, longType, enumType, { it }) { it?.idLong } -fun DatabaseConnection.registerDiscordStringMappers(bot: JDA, stringType: TypeMapper, enumType: TypeMapper?, *>? = null) = registerDiscordMappers(bot, stringType, enumType, { it.toLong() }) { it?.id } \ No newline at end of file +fun DatabaseConnection.registerDiscordLongMappers( + bot: JDA, + longType: TypeMapper, + enumType: TypeMapper?, *>? = null +) = registerDiscordMappers(bot, enumType, longType, { it }) { it?.idLong } + +fun DatabaseConnection.registerDiscordStringMappers( + bot: JDA, + stringType: TypeMapper, + enumType: TypeMapper?, *>? = null +) = registerDiscordMappers(bot, enumType, stringType, { it.toLong() }) { it?.id } \ No newline at end of file diff --git a/minecraft/src/main/kotlin/de/mineking/database/MinecraftMappers.kt b/minecraft/src/main/kotlin/de/mineking/database/MinecraftMappers.kt index caccba5..c26fd2a 100644 --- a/minecraft/src/main/kotlin/de/mineking/database/MinecraftMappers.kt +++ b/minecraft/src/main/kotlin/de/mineking/database/MinecraftMappers.kt @@ -1,5 +1,7 @@ package de.mineking.database +import net.kyori.adventure.text.format.NamedTextColor +import net.kyori.adventure.text.format.TextColor import org.bukkit.Location import org.bukkit.Server import org.bukkit.World @@ -14,15 +16,23 @@ import kotlin.reflect.typeOf @Retention(AnnotationRetention.RUNTIME) annotation class LocationWorldColumn(val name: String) -fun DatabaseConnection.registerMinecraftMappers(server: Server, uuidType: TypeMapper, arrayType: TypeMapper<*, Array<*>?>, doubleType: TypeMapper) { +fun DatabaseConnection.registerMinecraftMappers( + server: Server, + textType: TypeMapper? = null, + uuidType: TypeMapper? = null, + arrayType: TypeMapper<*, Array<*>?>? = null, + doubleType: TypeMapper? = null +) { data["server"] = server - typeMappers += typeMapper(uuidType, { it?.let { server.getOfflinePlayer(it) } }, { it?.uniqueId }) + if (uuidType != null) typeMappers += typeMapper(uuidType, { it?.let { server.getOfflinePlayer(it) } }, { it?.uniqueId }) + if (textType != null) typeMappers += typeMapper(textType, { it?.let { TextColor.fromHexString(it) } }, { it?.asHexString() }) + if (textType != null) typeMappers += typeMapper(textType, { it?.let { NamedTextColor.NAMES.value(it.lowercase()) } }, { it?.let { NamedTextColor.NAMES.key(it)?.uppercase() } }) - val worldMapper = typeMapper(uuidType, { it?.let { server.getWorld(it) } }, { it?.uid }) - typeMappers += worldMapper + val worldMapper = if (uuidType != null) typeMapper(uuidType, { it?.let { server.getWorld(it) } }, { it?.uid }) else null + if (worldMapper != null) typeMappers += worldMapper - typeMappers += object : TypeMapper?> { + if (worldMapper != null && doubleType != null && arrayType != null) typeMappers += object : TypeMapper?> { override fun accepts(manager: DatabaseConnection, property: KProperty<*>?, type: KType): Boolean = type.isSubtypeOf(typeOf()) override fun getType(column: ColumnData<*, *>?, table: TableStructure<*>, type: KType): DataType = arrayType.getType(column, table, typeOf>()) diff --git a/minecraft/src/test/kotlin/tests/minecraft/Color.kt b/minecraft/src/test/kotlin/tests/minecraft/Color.kt new file mode 100644 index 0000000..2c2e8a0 --- /dev/null +++ b/minecraft/src/test/kotlin/tests/minecraft/Color.kt @@ -0,0 +1,50 @@ +package tests.minecraft + +import de.mineking.database.* +import de.mineking.database.vendors.postgres.PostgresConnection +import de.mineking.database.vendors.postgres.PostgresMappers +import net.kyori.adventure.text.format.NamedTextColor +import net.kyori.adventure.text.format.TextColor +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import setup.ConsoleSqlLogger +import setup.createServer +import setup.recreate + +data class ColorDao( + @AutoIncrement @Key @Column val id: Int = 0, + @Column val color: TextColor = TextColor.color(0), + @Column val namedColor: NamedTextColor = NamedTextColor.BLACK +) + +class ColorTest { + val connection = PostgresConnection("localhost:5432/test", user = "test", password = "test") + val table: Table + + init { + connection.registerMinecraftMappers(createServer(), PostgresMappers.STRING, PostgresMappers.UUID_MAPPER, PostgresMappers.ARRAY, PostgresMappers.DOUBLE) + table = connection.getTable(name = "color_test") { ColorDao() } + + table.recreate() + + table.insert(ColorDao(color = TextColor.color(0x00ff00), namedColor = NamedTextColor.GREEN)) + + connection.driver.setSqlLogger(ConsoleSqlLogger) + } + + @Test + fun selectAll() { + val result = table.select().list() + + assertEquals(TextColor.color(0x00ff00), result[0].color) + assertEquals(NamedTextColor.GREEN, result[0].namedColor) + } + + @Test + fun selectColumn() { + assertEquals(TextColor.color(0x00ff00), table.select(property("color"), limit = 1).first()) + assertEquals(NamedTextColor.GREEN, table.select(property("namedColor"), limit = 1).first()) + + assertEquals(1, table.selectRowCount(where = property("color") isEqualTo value(TextColor.color(0x00ff00)))) + } +} \ No newline at end of file diff --git a/minecraft/src/test/kotlin/tests/minecraft/Location.kt b/minecraft/src/test/kotlin/tests/minecraft/Location.kt index 02d6585..23c88fc 100644 --- a/minecraft/src/test/kotlin/tests/minecraft/Location.kt +++ b/minecraft/src/test/kotlin/tests/minecraft/Location.kt @@ -33,7 +33,7 @@ class LocationTest { ) init { - connection.registerMinecraftMappers(createServer(worlds = worlds), PostgresMappers.UUID_MAPPER, PostgresMappers.ARRAY, PostgresMappers.DOUBLE) + connection.registerMinecraftMappers(createServer(worlds = worlds), PostgresMappers.STRING, PostgresMappers.UUID_MAPPER, PostgresMappers.ARRAY, PostgresMappers.DOUBLE) table = connection.getTable(name = "location_test") { LocationDao() } table.recreate() diff --git a/minecraft/src/test/kotlin/tests/minecraft/Player.kt b/minecraft/src/test/kotlin/tests/minecraft/Player.kt index af5b976..dc88d24 100644 --- a/minecraft/src/test/kotlin/tests/minecraft/Player.kt +++ b/minecraft/src/test/kotlin/tests/minecraft/Player.kt @@ -30,7 +30,7 @@ class PlayerTest { ) init { - connection.registerMinecraftMappers(createServer(players = players), PostgresMappers.UUID_MAPPER, PostgresMappers.ARRAY, PostgresMappers.DOUBLE) + connection.registerMinecraftMappers(createServer(players = players), PostgresMappers.STRING, PostgresMappers.UUID_MAPPER, PostgresMappers.ARRAY, PostgresMappers.DOUBLE) table = connection.getTable(name = "player_test") { PlayerDao() } table.recreate() diff --git a/postgres/src/main/kotlin/de/mineking/database/vendors/postgres/Conditions.kt b/postgres/src/main/kotlin/de/mineking/database/vendors/postgres/Conditions.kt index 5aa5461..3be4d84 100644 --- a/postgres/src/main/kotlin/de/mineking/database/vendors/postgres/Conditions.kt +++ b/postgres/src/main/kotlin/de/mineking/database/vendors/postgres/Conditions.kt @@ -1,6 +1,9 @@ package de.mineking.database.vendors.postgres -import de.mineking.database.* +import de.mineking.database.Node +import de.mineking.database.Where +import de.mineking.database.invoke +import de.mineking.database.value import kotlin.reflect.typeOf fun arrayLength(node: Node) = "array_length"(node) diff --git a/postgres/src/main/kotlin/de/mineking/database/vendors/postgres/PostgresTypes.kt b/postgres/src/main/kotlin/de/mineking/database/vendors/postgres/PostgresTypes.kt index 8a18c25..6d5cef3 100644 --- a/postgres/src/main/kotlin/de/mineking/database/vendors/postgres/PostgresTypes.kt +++ b/postgres/src/main/kotlin/de/mineking/database/vendors/postgres/PostgresTypes.kt @@ -6,6 +6,7 @@ import de.mineking.database.* import org.jdbi.v3.core.argument.Argument import org.jdbi.v3.core.statement.StatementContext import org.postgresql.util.PGobject +import java.awt.Color import java.math.BigDecimal import java.math.BigInteger import java.sql.* @@ -88,6 +89,9 @@ object PostgresMappers { val ZONED_DATE_TIME = typeMapper(PostgresType.TIMESTAMPTZ, { set, name -> set.getObject(name, OffsetDateTime::class.java).toZonedDateTime() }, { value, statement, position -> statement.setTimestamp(position, value?.let { Timestamp.valueOf(it.toLocalDateTime()) }) }) val LOCAL_DATE = typeMapper(PostgresType.DATE, { set, name -> set.getDate(name).toLocalDate() }, { value, statement, position -> statement.setDate(position, value?.let { Date.valueOf(it) }) }) + val LOCALE = typeMapper(STRING, { it?.let { Locale.forLanguageTag(it) } }, { it?.toLanguageTag() }) + val COLOR = typeMapper(INTEGER, { it?.let { Color(it, true) } }, { it?.rgb }) + val ARRAY = object : TypeMapper?> { fun Any.asArray(): Array<*> = when (this) { is Array<*> -> this diff --git a/postgres/src/test/kotlin/tests/postgres/specific/Color.kt b/postgres/src/test/kotlin/tests/postgres/specific/Color.kt new file mode 100644 index 0000000..8590ee3 --- /dev/null +++ b/postgres/src/test/kotlin/tests/postgres/specific/Color.kt @@ -0,0 +1,32 @@ +package tests.postgres.specific + +import de.mineking.database.* +import de.mineking.database.vendors.postgres.PostgresConnection +import org.junit.jupiter.api.Test +import setup.ConsoleSqlLogger +import setup.recreate +import java.awt.Color +import kotlin.test.assertEquals + +data class ColorDao( + @AutoIncrement @Key @Column val id: Int = 0, + @Column val color: Color = Color.WHITE +) + +class ColorTest { + val connection = PostgresConnection("localhost:5432/test", user = "test", password = "test") + val table = connection.getTable(name = "color_test") { ColorDao() } + + init { + table.recreate() + + table.insert(ColorDao(color = Color.GREEN)) + + connection.driver.setSqlLogger(ConsoleSqlLogger) + } + + @Test + fun selectAll() { + assertEquals(Color.GREEN, table.select(property("color")).first()) + } +} \ No newline at end of file diff --git a/postgres/src/test/kotlin/tests/postgres/specific/Locale.kt b/postgres/src/test/kotlin/tests/postgres/specific/Locale.kt new file mode 100644 index 0000000..2eec8ea --- /dev/null +++ b/postgres/src/test/kotlin/tests/postgres/specific/Locale.kt @@ -0,0 +1,32 @@ +package tests.postgres.specific + +import de.mineking.database.* +import de.mineking.database.vendors.postgres.PostgresConnection +import org.junit.jupiter.api.Test +import setup.ConsoleSqlLogger +import setup.recreate +import java.util.* +import kotlin.test.assertEquals + +data class LocaleDao( + @AutoIncrement @Key @Column val id: Int = 0, + @Column val locale: Locale = Locale.ENGLISH, +) + +class LocaleTest { + val connection = PostgresConnection("localhost:5432/test", user = "test", password = "test") + val table = connection.getTable(name = "locale_test") { LocaleDao() } + + init { + table.recreate() + + table.insert(LocaleDao(locale = Locale.GERMAN)) + + connection.driver.setSqlLogger(ConsoleSqlLogger) + } + + @Test + fun selectAll() { + assertEquals(Locale.GERMAN, table.select(property("locale")).first()) + } +} \ No newline at end of file diff --git a/sqlite/src/main/kotlin/de/mineking/database/vendors/sqlite/SQLiteTypes.kt b/sqlite/src/main/kotlin/de/mineking/database/vendors/sqlite/SQLiteTypes.kt index 4ef9211..738d718 100644 --- a/sqlite/src/main/kotlin/de/mineking/database/vendors/sqlite/SQLiteTypes.kt +++ b/sqlite/src/main/kotlin/de/mineking/database/vendors/sqlite/SQLiteTypes.kt @@ -5,14 +5,17 @@ import com.google.gson.ToNumberStrategy import de.mineking.database.* import org.jdbi.v3.core.argument.Argument import org.jdbi.v3.core.statement.StatementContext +import java.awt.Color import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.ObjectInputStream import java.io.ObjectOutputStream import java.sql.* +import java.sql.Date import java.time.Instant import java.time.LocalDate import java.time.LocalDateTime +import java.util.* import kotlin.reflect.KProperty import kotlin.reflect.KType import kotlin.reflect.jvm.javaType @@ -77,6 +80,9 @@ object SQLiteMappers { val LOCAL_DATE_TIME = typeMapper(SQLiteType.INTEGER, { set, name -> set.getTimestamp(name).toLocalDateTime() }, { value, statement, position -> statement.setTimestamp(position, value?.let { Timestamp.valueOf(it) }) }) val LOCAL_DATE = typeMapper(SQLiteType.INTEGER, { set, name -> set.getDate(name).toLocalDate() }, { value, statement, position -> statement.setDate(position, value?.let { Date.valueOf(it) }) }) + val LOCALE = typeMapper(STRING, { it?.let { Locale.forLanguageTag(it) } }, { it?.toLanguageTag() }) + val COLOR = typeMapper(INTEGER, { it?.let { Color(it, true) } }, { it?.rgb }) + val ARRAY = object : TypeMapper { fun Any.asArray(): Array<*> = when (this) { is Array<*> -> this diff --git a/sqlite/src/test/kotlin/tests/sqlite/specific/Color.kt b/sqlite/src/test/kotlin/tests/sqlite/specific/Color.kt new file mode 100644 index 0000000..bd3bc3c --- /dev/null +++ b/sqlite/src/test/kotlin/tests/sqlite/specific/Color.kt @@ -0,0 +1,32 @@ +package tests.sqlite.specific + +import de.mineking.database.* +import de.mineking.database.vendors.sqlite.SQLiteConnection +import org.junit.jupiter.api.Test +import setup.ConsoleSqlLogger +import setup.recreate +import java.awt.Color +import kotlin.test.assertEquals + +data class ColorDao( + @AutoIncrement @Key @Column val id: Int = 0, + @Column val color: Color = Color.WHITE +) + +class ColorTest { + val connection = SQLiteConnection("test.db") + val table = connection.getTable(name = "color_test") { ColorDao() } + + init { + table.recreate() + + table.insert(ColorDao(color = Color.GREEN)) + + connection.driver.setSqlLogger(ConsoleSqlLogger) + } + + @Test + fun selectAll() { + assertEquals(Color.GREEN, table.select(property("color")).first()) + } +} \ No newline at end of file diff --git a/sqlite/src/test/kotlin/tests/sqlite/specific/Locale.kt b/sqlite/src/test/kotlin/tests/sqlite/specific/Locale.kt new file mode 100644 index 0000000..3589e64 --- /dev/null +++ b/sqlite/src/test/kotlin/tests/sqlite/specific/Locale.kt @@ -0,0 +1,32 @@ +package tests.sqlite.specific + +import de.mineking.database.* +import de.mineking.database.vendors.sqlite.SQLiteConnection +import org.junit.jupiter.api.Test +import setup.ConsoleSqlLogger +import setup.recreate +import java.util.* +import kotlin.test.assertEquals + +data class LocaleDao( + @AutoIncrement @Key @Column val id: Int = 0, + @Column val locale: Locale = Locale.ENGLISH, +) + +class LocaleTest { + val connection = SQLiteConnection("test.db") + val table = connection.getTable(name = "locale_test") { LocaleDao() } + + init { + table.recreate() + + table.insert(LocaleDao(locale = Locale.GERMAN)) + + connection.driver.setSqlLogger(ConsoleSqlLogger) + } + + @Test + fun selectAll() { + assertEquals(Locale.GERMAN, table.select(property("locale")).first()) + } +} \ No newline at end of file