Skip to content

Commit

Permalink
fix: EXPOSED-389 Coalesce operator returning nullable value (#2107)
Browse files Browse the repository at this point in the history
The Coalesce function was returning a nullable type when it shouldn't.

(cherry picked from commit ff613fa)
  • Loading branch information
joc-a committed Jun 3, 2024
1 parent f97820f commit 184c7ec
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -438,11 +438,12 @@ class CaseWhenElse<T>(
/**
* Represents an SQL function that returns the first of its arguments that is not null.
*/
class Coalesce<out T, S : T?>(
@Suppress("UNCHECKED_CAST")
class Coalesce<T, S : T?>(
private val expr: ExpressionWithColumnType<S>,
private val alternate: Expression<out T>,
private vararg val others: Expression<out T>
) : Function<S>(expr.columnType) {
) : Function<T>(expr.columnType as IColumnType<T & Any>) {
override fun toQueryBuilder(queryBuilder: QueryBuilder): Unit = queryBuilder {
(listOf(expr, alternate) + others).appendTo(
prefix = "COALESCE(",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ interface ISqlExpressionBuilder {
expr: ExpressionWithColumnType<S>,
alternate: Expression<out T>,
vararg others: Expression<out T>
): Coalesce<T?, S> = Coalesce(expr, alternate, others = others)
): Coalesce<T, S> = Coalesce<T, S>(expr, alternate, others = others)

/**
* Compares [value] against any chained conditional expressions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.jetbrains.exposed.sql.tests.shared.functions

import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.coalesce
import org.jetbrains.exposed.sql.SqlExpressionBuilder.concat
import org.jetbrains.exposed.sql.tests.DatabaseTestsBase
import org.jetbrains.exposed.sql.tests.TestDB
Expand All @@ -10,7 +11,11 @@ import org.jetbrains.exposed.sql.tests.shared.assertEqualCollections
import org.jetbrains.exposed.sql.tests.shared.assertEquals
import org.jetbrains.exposed.sql.tests.shared.dml.DMLTestsData
import org.jetbrains.exposed.sql.tests.shared.dml.withCitiesAndUsers
import org.jetbrains.exposed.sql.vendors.*
import org.jetbrains.exposed.sql.vendors.H2Dialect
import org.jetbrains.exposed.sql.vendors.MysqlDialect
import org.jetbrains.exposed.sql.vendors.OracleDialect
import org.jetbrains.exposed.sql.vendors.SQLServerDialect
import org.jetbrains.exposed.sql.vendors.h2Mode
import org.junit.Test
import kotlin.test.assertNotNull
import kotlin.test.assertNull
Expand Down Expand Up @@ -570,25 +575,27 @@ class FunctionsTests : DatabaseTestsBase() {
@Test
fun testCoalesceFunction() {
withCitiesAndUsers { _, users, _ ->
val coalesceExp1 = Coalesce(users.cityId, intLiteral(1000))
val coalesceExp1 = coalesce(users.cityId, intLiteral(1000))

users.select(users.cityId, coalesceExp1).forEach {
val cityId = it[users.cityId]
val actual: Int = it[coalesceExp1]
if (cityId != null) {
assertEquals(cityId, it[coalesceExp1])
assertEquals(cityId, actual)
} else {
assertEquals(1000, it[coalesceExp1])
assertEquals(1000, actual)
}
}

val coalesceExp2 = Coalesce(users.cityId, Op.nullOp<Int>(), intLiteral(1000))

users.select(users.cityId, coalesceExp2).forEach {
val cityId = it[users.cityId]
val actual: Int = it[coalesceExp2]
if (cityId != null) {
assertEquals(cityId, it[coalesceExp2])
assertEquals(cityId, actual)
} else {
assertEquals(1000, it[coalesceExp2])
assertEquals(1000, actual)
}
}
}
Expand Down

0 comments on commit 184c7ec

Please sign in to comment.