Skip to content

Commit

Permalink
Support update { it[column] = nullableValue }
Browse files Browse the repository at this point in the history
Key change is UpdateBuilder#setWithEntityIdValue, which now accepts
column: Column<out EntityID<S>?>, value: S?
previous signature was
column: Column<out EntityID<S>>, value: S?

A downside is that "[optionalReferenceColumn] = null" can't decide between
"null as ColumnType?" and "null as EntityID<ColumnType>?"

update {
  // it[optionalReferenceColumn] = null // <- does not work
  // Workaround: specify null type explicitly to call the proper overload
  it[optionalReferenceColumn] = null as EntityID<ColumnType>?
  // The following works as well:
  // it[optionalReferenceColumn] = null as ColumnType?
}

fixes JetBrains#1275
  • Loading branch information
vlsi committed Jun 19, 2021
1 parent 2c616ec commit 36e4cf6
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ open class BatchUpdateStatement(val table: IdTable<*>) : UpdateStatement(table,
data.add(id to values)
}

override fun <T, S : T?> update(column: Column<T>, value: Expression<S>) = error("Expressions unsupported in batch update")
override fun <T> update(column: Column<T>, value: Expression<out T>) = error("Expressions unsupported in batch update")

override fun prepareSQL(transaction: Transaction): String =
"${super.prepareSQL(transaction)} WHERE ${transaction.identity(table.id)} = ?"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,32 @@ abstract class UpdateBuilder<out T>(type: StatementType, targets: List<Table>) :
}

@JvmName("setWithEntityIdExpression")
operator fun <S, ID : EntityID<S>, E : Expression<S>> set(column: Column<ID>, value: E) {
operator fun <S : Comparable<S>> set(column: Column<out EntityID<S>?>, value: Expression<out S?>) {
require(!values.containsKey(column)) { "$column is already initialized" }
column.columnType.validateValueBeforeUpdate(value)
values[column] = value
}

@JvmName("setWithEntityIdValue")
operator fun <S : Comparable<S>, ID : EntityID<S>, E : S?> set(column: Column<ID>, value: E) {
operator fun <S : Comparable<S>> set(column: Column<out EntityID<S>?>, value: S?) {
require(!values.containsKey(column)) { "$column is already initialized" }
column.columnType.validateValueBeforeUpdate(value)
values[column] = value
}

open operator fun <T, S : T, E : Expression<S>> set(column: Column<T>, value: E) = update(column, value)
open operator fun <S> set(column: Column<S>, value: Expression<out S>) = update(column, value)

open operator fun <S> set(column: CompositeColumn<S>, value: S) {
column.getRealColumnsWithValues(value).forEach { (realColumn, itsValue) -> set(realColumn as Column<Any?>, itsValue) }
}

open fun <T, S : T?> update(column: Column<T>, value: Expression<S>) {
open fun <S> update(column: Column<S>, value: Expression<out S>) {
require(!values.containsKey(column)) { "$column is already initialized" }
column.columnType.validateValueBeforeUpdate(value)
values[column] = value
}

open fun <T, S : T?> update(column: Column<T>, value: SqlExpressionBuilder.() -> Expression<S>) {
open fun <S> update(column: Column<S>, value: SqlExpressionBuilder.() -> Expression<out S>) {
require(!values.containsKey(column)) { "$column is already initialized" }
val expression = SqlExpressionBuilder.value()
column.columnType.validateValueBeforeUpdate(expression)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,17 @@ class DDLTests : DatabaseTestsBase() {
assertEquals(2L, Table2.selectAll().count())

Table2.update {
it[table1] = null
}

Table2.update {
// = null can't decide between "null as Int?" and "null as EntityID<Int?>"
// it[table1] = null
it[table1] = null as Int?
}
Table2.update {
// = null can't decide between "null as Int?" and "null as EntityID<Int>?"
// it[table1] = null
it[table1] = null as EntityID<Int>?
}

Table1.deleteAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IdTable
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.UpdateBuilder
import org.jetbrains.exposed.sql.tests.DatabaseTestsBase
import org.jetbrains.exposed.sql.tests.TestDB
import org.jetbrains.exposed.sql.tests.currentDialectTest
import org.jetbrains.exposed.sql.tests.shared.*
import org.jetbrains.exposed.sql.tests.shared.assertEqualLists
import org.jetbrains.exposed.sql.tests.shared.assertEquals
import org.jetbrains.exposed.sql.tests.shared.assertFailAndRollback
import org.jetbrains.exposed.sql.tests.shared.expectException
import org.jetbrains.exposed.sql.vendors.MysqlDialect
import org.junit.Test
import java.math.BigDecimal
Expand Down Expand Up @@ -230,33 +234,37 @@ class InsertTests : DatabaseTestsBase() {
val string = varchar("stringCol", 20)
}

fun expression(value: String) = stringLiteral(value).trim().substring(2, 4)
fun<T:Table> T.verifyInsert(expectedIntValue: Int?, insertClause: T.(UpdateBuilder<Int>) -> Unit) {
fun expression(value: String) = stringLiteral(value).trim().substring(2, 4)

fun verify(value: String) {
val row = tbl.select { tbl.string eq value }.single()
assertEquals(row[tbl.string], value)
deleteAll()
insert {
it[tbl.string] = expression(" _test_ ")
insertClause(it)
}
val rows = selectAll().adjustSlice { slice(tbl.string, tbl.nullableInt) }
.map { mapOf("string" to it[tbl.string], "nullableInt" to it[tbl.nullableInt]) }
assertEquals(
listOf(mapOf("string" to "test", "nullableInt" to expectedIntValue)).toString(),
rows.toString()
)
}

withTables(tbl) {
tbl.insert {
it[string] = expression(" _exp1_ ")
tbl.verifyInsert(null) {
}

verify("exp1")

tbl.insert {
it[string] = expression(" _exp2_ ")
tbl.verifyInsert(5) {
it[nullableInt] = 5
}

verify("exp2")

tbl.insert {
it[string] = expression(" _exp3_ ")
tbl.verifyInsert(null) {
it[nullableInt] = null
}

verify("exp3")
tbl.verifyInsert(null) {
it[nullableInt] = LiteralOp(nullableInt.columnType, null)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,26 @@ class EntityTests : DatabaseTestsBase() {
}
}

@Test
fun testOptionalReference() {
withTables(EntityTestsData.XTable, EntityTestsData.YTable) {
val y = EntityTestsData.YEntity.new { }
EntityTestsData.XTable.insert {
it[y1] = y.id
}
EntityTestsData.XTable.insert {
// = null can't decide between "null as String?" and "null as EntityId<String>?"
// it[EntityTestsData.XTable.y1] = null
it[y1] = null as String?
}
EntityTestsData.XTable.insert {
// = null can't decide between "null as String?" and "null as EntityID<String>?"
// it[EntityTestsData.XTable.y1] = null
it[y1] = null as EntityID<String>?
}
}
}

object Boards : IntIdTable(name = "board") {
val name = varchar("name", 255).index(isUnique = true)
}
Expand Down

0 comments on commit 36e4cf6

Please sign in to comment.