org.jetbrains.exposed.dao.EntityLifecycleInterceptor.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of exposed-dao Show documentation
Show all versions of exposed-dao Show documentation
Exposed, an ORM framework for Kotlin
package org.jetbrains.exposed.dao
import org.jetbrains.exposed.dao.id.IdTable
import org.jetbrains.exposed.sql.Key
import org.jetbrains.exposed.sql.Query
import org.jetbrains.exposed.sql.Transaction
import org.jetbrains.exposed.sql.statements.*
import org.jetbrains.exposed.sql.statements.api.PreparedStatementApi
import org.jetbrains.exposed.sql.targetTables
import org.jetbrains.exposed.sql.transactions.transactionScope
private var isExecutedWithinEntityLifecycle by transactionScope { false }
internal fun executeAsPartOfEntityLifecycle(body: () -> T): T {
val currentExecutionState = isExecutedWithinEntityLifecycle
return try {
isExecutedWithinEntityLifecycle = true
body()
} finally {
isExecutedWithinEntityLifecycle = currentExecutionState
}
}
/**
* Represents a [StatementInterceptor] specifically responsible for the statement lifecycle of [Entity] instances,
* which is loaded whenever a [Transaction] instance is initialized.
*/
class EntityLifecycleInterceptor : GlobalStatementInterceptor {
override fun keepUserDataInTransactionStoreOnCommit(userData: Map, Any?>): Map, Any?> {
return userData.filterValues { it is EntityCache }
}
@Suppress("ComplexMethod")
override fun beforeExecution(transaction: Transaction, context: StatementContext) {
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)
if (!isExecutedWithinEntityLifecycle) {
statement.targets.filterIsInstance>().forEach {
transaction.entityCache.data[it]?.clear()
}
}
}
is UpsertStatement<*>, is BatchUpsertStatement -> {
transaction.flushCache()
transaction.entityCache.removeTablesReferrers(statement.targets, true)
if (!isExecutedWithinEntityLifecycle) {
statement.targets.filterIsInstance>().forEach {
transaction.entityCache.data[it]?.clear()
}
}
}
is InsertStatement<*> -> {
transaction.flushCache()
transaction.entityCache.removeTablesReferrers(listOf(statement.table), true)
}
is BatchUpdateStatement -> {
}
is UpdateStatement -> {
transaction.flushCache()
transaction.entityCache.removeTablesReferrers(statement.targetsSet.targetTables(), false)
if (!isExecutedWithinEntityLifecycle) {
statement.targets.filterIsInstance>().forEach {
transaction.entityCache.data[it]?.clear()
}
}
}
else -> {
if (statement.type.group == StatementGroup.DDL) transaction.flushCache()
}
}
}
override fun afterExecution(transaction: Transaction, contexts: List, executedStatement: PreparedStatementApi) {
if (!isExecutedWithinEntityLifecycle || contexts.first().statement !is InsertStatement<*>) {
transaction.alertSubscribers()
}
}
override fun beforeCommit(transaction: Transaction) {
val created = transaction.flushCache()
transaction.alertSubscribers()
val createdByHooks = transaction.flushCache()
EntityCache.invalidateGlobalCaches(created + createdByHooks)
}
override fun beforeRollback(transaction: Transaction) {
val entityCache = transaction.entityCache
entityCache.clearReferrersCache()
entityCache.data.clear()
entityCache.inserts.clear()
}
private fun Transaction.flushEntities(query: Query) {
// Flush data before executing query or results may be unpredictable
val tables = query.targets.filterIsInstance(IdTable::class.java).toSet()
entityCache.flush(tables)
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy