diff --git a/exposed-json/api/exposed-json.api b/exposed-json/api/exposed-json.api index e668b97713..4a65d55fd6 100644 --- a/exposed-json/api/exposed-json.api +++ b/exposed-json/api/exposed-json.api @@ -46,6 +46,7 @@ public class org/jetbrains/exposed/sql/json/JsonColumnType : org/jetbrains/expos public fun setParameter (Lorg/jetbrains/exposed/sql/statements/api/PreparedStatementApi;ILjava/lang/Object;)V public fun sqlType ()Ljava/lang/String; public fun valueFromDB (Ljava/lang/Object;)Ljava/lang/Object; + public fun valueToString (Ljava/lang/Object;)Ljava/lang/String; } public final class org/jetbrains/exposed/sql/json/JsonColumnTypeKt { diff --git a/exposed-json/src/main/kotlin/org/jetbrains/exposed/sql/json/JsonColumnType.kt b/exposed-json/src/main/kotlin/org/jetbrains/exposed/sql/json/JsonColumnType.kt index 6780b0e595..a74541ad57 100644 --- a/exposed-json/src/main/kotlin/org/jetbrains/exposed/sql/json/JsonColumnType.kt +++ b/exposed-json/src/main/kotlin/org/jetbrains/exposed/sql/json/JsonColumnType.kt @@ -38,6 +38,11 @@ open class JsonColumnType( @Suppress("UNCHECKED_CAST") override fun notNullValueToDB(value: Any) = serialize(value as T) + override fun valueToString(value: Any?): String = when (value) { + is Iterable<*> -> nonNullValueToString(value) + else -> super.valueToString(value) + } + override fun nonNullValueToString(value: Any): String { return when (currentDialect) { is H2Dialect -> "JSON '${notNullValueToDB(value)}'" diff --git a/exposed-json/src/test/kotlin/org/jetbrains/exposed/sql/json/JsonBColumnTests.kt b/exposed-json/src/test/kotlin/org/jetbrains/exposed/sql/json/JsonBColumnTests.kt index a3b7654618..6cbe09554d 100644 --- a/exposed-json/src/test/kotlin/org/jetbrains/exposed/sql/json/JsonBColumnTests.kt +++ b/exposed-json/src/test/kotlin/org/jetbrains/exposed/sql/json/JsonBColumnTests.kt @@ -1,5 +1,8 @@ package org.jetbrains.exposed.sql.json +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.builtins.ArraySerializer +import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.jetbrains.exposed.exceptions.UnsupportedByDialectException @@ -15,6 +18,7 @@ import org.jetbrains.exposed.sql.tests.shared.assertTrue import org.jetbrains.exposed.sql.tests.shared.expectException import org.jetbrains.exposed.sql.vendors.PostgreSQLDialect import org.junit.Test +import kotlin.test.assertContentEquals class JsonBColumnTests : DatabaseTestsBase() { private val binaryJsonNotSupportedDB = listOf(TestDB.SQLITE, TestDB.SQLSERVER) + TestDB.ORACLE @@ -264,4 +268,42 @@ class JsonBColumnTests : DatabaseTestsBase() { } } } + + @OptIn(ExperimentalSerializationApi::class) + @Test + fun testLoggerWithJsonBCollections() { + val iterables = object : Table("iterables_tester") { + val userList = jsonb("user_list", Json.Default, ListSerializer(User.serializer())) + val intList = jsonb>("int_list", Json.Default) + val userArray = jsonb("user_array", Json.Default, ArraySerializer(User.serializer())) + val intArray = jsonb("int_array", Json.Default) + } + + withDb(excludeSettings = binaryJsonNotSupportedDB) { testDb -> + excludingH2Version1(testDb) { + // the logger is left in to test that it does not throw ClassCastException on insertion of iterables + addLogger(StdOutSqlLogger) + SchemaUtils.create(iterables) + + val user1 = User("A", "Team A") + val user2 = User("B", "Team B") + val integerList = listOf(1, 2, 3) + val integerArray = intArrayOf(1, 2, 3) + iterables.insert { + it[userList] = listOf(user1, user2) + it[intList] = integerList + it[userArray] = arrayOf(user1, user2) + it[intArray] = integerArray + } + + val result = iterables.selectAll().single() + assertEqualCollections(listOf(user1, user2), result[iterables.userList]) + assertEqualCollections(integerList, result[iterables.intList]) + assertContentEquals(arrayOf(user1, user2), result[iterables.userArray]) + assertContentEquals(integerArray, result[iterables.intArray]) + + SchemaUtils.drop(iterables) + } + } + } } diff --git a/exposed-json/src/test/kotlin/org/jetbrains/exposed/sql/json/JsonColumnTests.kt b/exposed-json/src/test/kotlin/org/jetbrains/exposed/sql/json/JsonColumnTests.kt index 717f6e2a08..887275fe71 100644 --- a/exposed-json/src/test/kotlin/org/jetbrains/exposed/sql/json/JsonColumnTests.kt +++ b/exposed-json/src/test/kotlin/org/jetbrains/exposed/sql/json/JsonColumnTests.kt @@ -1,6 +1,9 @@ package org.jetbrains.exposed.sql.json +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.SerializationException +import kotlinx.serialization.builtins.ArraySerializer +import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.jetbrains.exposed.exceptions.UnsupportedByDialectException @@ -18,6 +21,7 @@ import org.jetbrains.exposed.sql.vendors.OracleDialect import org.jetbrains.exposed.sql.vendors.PostgreSQLDialect import org.jetbrains.exposed.sql.vendors.SQLServerDialect import org.junit.Test +import kotlin.test.assertContentEquals class JsonColumnTests : DatabaseTestsBase() { @Test @@ -299,4 +303,42 @@ class JsonColumnTests : DatabaseTestsBase() { } } } + + @OptIn(ExperimentalSerializationApi::class) + @Test + fun testLoggerWithJsonCollections() { + val iterables = object : Table("iterables_tester") { + val userList = json("user_list", Json.Default, ListSerializer(User.serializer())) + val intList = json>("int_list", Json.Default) + val userArray = json("user_array", Json.Default, ArraySerializer(User.serializer())) + val intArray = json("int_array", Json.Default) + } + + withDb { testDb -> + excludingH2Version1(testDb) { + // the logger is left in to test that it does not throw ClassCastException on insertion of iterables + addLogger(StdOutSqlLogger) + SchemaUtils.create(iterables) + + val user1 = User("A", "Team A") + val user2 = User("B", "Team B") + val integerList = listOf(1, 2, 3) + val integerArray = intArrayOf(1, 2, 3) + iterables.insert { + it[userList] = listOf(user1, user2) + it[intList] = integerList + it[userArray] = arrayOf(user1, user2) + it[intArray] = integerArray + } + + val result = iterables.selectAll().single() + assertEqualCollections(listOf(user1, user2), result[iterables.userList]) + assertEqualCollections(integerList, result[iterables.intList]) + assertContentEquals(arrayOf(user1, user2), result[iterables.userArray]) + assertContentEquals(integerArray, result[iterables.intArray]) + + SchemaUtils.drop(iterables) + } + } + } }