Skip to content

Commit

Permalink
[BUG FIX] Fix entity cache for returning statements
Browse files Browse the repository at this point in the history
We were noticing weird issues where DAOs returned using upsertReturning had stale values.
We pinned it down to the EntityLifecycleInterceptor not correctly handling ReturningStatement upsertStatement cache evictions.

The test I’ve added validates this and will fail without my changes.
  • Loading branch information
rasharab committed Sep 22, 2024
1 parent d3c60f2 commit 32214ac
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,17 @@ class EntityLifecycleInterceptor : GlobalStatementInterceptor {

@Suppress("ComplexMethod")
override fun beforeExecution(transaction: Transaction, context: StatementContext) {
when (val statement = context.statement) {
beforeExecution(transaction = transaction, context = context, childStatement = null)
}

private fun beforeExecution(transaction: Transaction, context: StatementContext, childStatement: Statement<*>?) {
when (val statement = childStatement ?: context.statement) {
is Query -> transaction.flushEntities(statement)

is ReturningStatement -> {
beforeExecution(transaction = transaction, context = context, childStatement = statement.mainStatement)
}

is DeleteStatement -> {
transaction.flushCache()
transaction.entityCache.removeTablesReferrers(statement.targetsSet.targetTables(), false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.jetbrains.exposed.sql.tests.shared.dml

import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.times
Expand All @@ -21,6 +24,13 @@ class ReturningTests : DatabaseTestsBase() {
val price = double("price")
}

class ItemDAO(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<ItemDAO>(Items)

var name by Items.name
var price by Items.price
}

@Test
fun testInsertReturning() {
withTables(TestDB.ALL - returningSupportedDb, Items) {
Expand Down Expand Up @@ -115,6 +125,34 @@ class ReturningTests : DatabaseTestsBase() {
}
}

@Test
fun testUpsertReturningWithDAO() {
withTables(TestDB.ALL - returningSupportedDb, Items) {
val result1 = Items.upsertReturning {
it[name] = "A"
it[price] = 99.0
}.let {
ItemDAO.wrapRow(it.single())
}
assertEquals(1, result1.id.value)
assertEquals("A", result1.name)
assertEquals(99.0, result1.price)

val result2 = Items.upsertReturning {
it[id] = 1
it[name] = "B"
it[price] = 200.0
}.let {
ItemDAO.wrapRow(it.single())
}
assertEquals(1, result2.id.value)
assertEquals("B", result2.name)
assertEquals(200.0, result2.price)

assertEquals(1, Items.selectAll().count())
}
}

@Test
fun testReturningWithNoResults() {
withTables(TestDB.enabledDialects() - returningSupportedDb, Items) {
Expand Down

0 comments on commit 32214ac

Please sign in to comment.