diff --git a/documentation-website/Writerside/topics/Breaking-Changes.md b/documentation-website/Writerside/topics/Breaking-Changes.md index 0db095eab1..59f9381b5a 100644 --- a/documentation-website/Writerside/topics/Breaking-Changes.md +++ b/documentation-website/Writerside/topics/Breaking-Changes.md @@ -24,6 +24,7 @@ values are inserted. * The transformation of a nullable column (`Column.transform()`) requires handling null values. This enables conversions from `null` to a non-nullable value, and vice versa. +* In H2 the definition of json column with default value changed from `myColumn JSON DEFAULT '{"key": "value"}'` to `myColumn JSON DEFAULT JSON '{"key": "value"}'` ## 0.54.0 diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt index a86fbd280e..17e8c8226a 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt @@ -214,7 +214,10 @@ object SchemaUtils { is MariaDBDialect -> processed.trim('\'') is MysqlDialect -> "_utf8mb4\\'${processed.trim('(', ')', '\'')}\\'" - else -> processed.trim('\'') + else -> when { + processed.startsWith('\'') && processed.endsWith('\'') -> processed.trim('\'') + else -> processed + } } } diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DataTypeProvider.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DataTypeProvider.kt index 6f38ecc71b..fbd20a0486 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DataTypeProvider.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DataTypeProvider.kt @@ -141,12 +141,6 @@ abstract class DataTypeProvider { /** Returns the SQL representation of the specified expression, for it to be used as a column default value. */ open fun processForDefaultValue(e: Expression<*>): String = when { - e is LiteralOp<*> && e.columnType is JsonColumnMarker -> if (currentDialect is H2Dialect) { - "$e".substringAfter("JSON ") - } else { - "'$e'" - } - e is LiteralOp<*> -> (e.columnType as IColumnType).valueAsDefaultString(e.value) e is Function<*> -> "$e" currentDialect is MysqlDialect -> "$e" diff --git a/exposed-json/api/exposed-json.api b/exposed-json/api/exposed-json.api index 9d39bc9584..fe81099b08 100644 --- a/exposed-json/api/exposed-json.api +++ b/exposed-json/api/exposed-json.api @@ -40,6 +40,7 @@ public class org/jetbrains/exposed/sql/json/JsonColumnType : org/jetbrains/expos public final fun getDeserialize ()Lkotlin/jvm/functions/Function1; public final fun getSerialize ()Lkotlin/jvm/functions/Function1; public fun getUsesBinaryFormat ()Z + public fun nonNullValueAsDefaultString (Ljava/lang/Object;)Ljava/lang/String; public fun nonNullValueToString (Ljava/lang/Object;)Ljava/lang/String; public fun notNullValueToDB (Ljava/lang/Object;)Ljava/lang/Object; public fun parameterMarker (Ljava/lang/Object;)Ljava/lang/String; 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 63b07e0ed2..5262d82a38 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 @@ -71,6 +71,13 @@ open class JsonColumnType( } super.setParameter(stmt, index, parameterValue) } + + override fun nonNullValueAsDefaultString(value: T): String { + return when { + currentDialect is H2Dialect -> "JSON '${notNullValueToDB(value)}'" + else -> "'${notNullValueToDB(value)}'" + } + } } /** 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 b47be2a04c..2d50a05859 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 @@ -425,4 +425,26 @@ class JsonColumnTests : DatabaseTestsBase() { assertContentEquals(data, tester.selectAll().single()[tester.numbers]) } } + + @Test + fun testJsonAsDefault() { + val defaultUser = User("name", "team") + val tester = object : IntIdTable("testJsonAsDefault") { + val value = json("value", Json.Default) + .default(defaultUser) + } + + val testerDatabaseGenerated = object : IntIdTable("testJsonAsDefault") { + val value = json("value", Json.Default) + .databaseGenerated() + } + + // MySQL versions prior to 8.0.13 do not accept default values on JSON columns + withTables(excludeSettings = listOf(TestDB.MYSQL_V5), tester) { + testerDatabaseGenerated.insert { } + + val value = testerDatabaseGenerated.selectAll().single()[tester.value] + assertEquals(defaultUser, value) + } + } }