Skip to content

Commit

Permalink
fix!: EXPOSED-546 [H2] Column with Json default value can not be used…
Browse files Browse the repository at this point in the history
… as databaseGenerated (#2241)
  • Loading branch information
obabichevjb authored Sep 19, 2024
1 parent baf3add commit 3c0a251
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
values are inserted.
* The transformation of a nullable column (`Column<Unwrapped?>.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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Any?>).valueAsDefaultString(e.value)
e is Function<*> -> "$e"
currentDialect is MysqlDialect -> "$e"
Expand Down
1 change: 1 addition & 0 deletions exposed-json/api/exposed-json.api
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ open class JsonColumnType<T : Any>(
}
super.setParameter(stmt, index, parameterValue)
}

override fun nonNullValueAsDefaultString(value: T): String {
return when {
currentDialect is H2Dialect -> "JSON '${notNullValueToDB(value)}'"
else -> "'${notNullValueToDB(value)}'"
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<User>("value", Json.Default)
.default(defaultUser)
}

val testerDatabaseGenerated = object : IntIdTable("testJsonAsDefault") {
val value = json<User>("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)
}
}
}

0 comments on commit 3c0a251

Please sign in to comment.