Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: EXPOSED-546 [H2] Column with Json default value can not be used as databaseGenerated #2241

Merged
merged 1 commit into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
}
}
Loading