Logic Delete
This chapter describes logical delete behavior in mutation APIs.
Declare the logical delete column
Use @LogicDelete on the KPojo field that marks deleted rows. The annotation is enabled by default.
User.kt
import com.kotlinorm.annotations.Default
import com.kotlinorm.annotations.LogicDelete
import com.kotlinorm.annotations.PrimaryKey
import com.kotlinorm.interfaces.KPojo
data class User(
@PrimaryKey(identity = true)
var id: Int? = null,
var name: String? = null,
@LogicDelete
@Default("0") // @Default("false") for Postgres
var deleted: Boolean? = null
) : KPojoIf your application uses the same logical delete field across tables, configure the global strategy and keep the field on each KPojo that should use it.
global config
import com.kotlinorm.Kronos
import com.kotlinorm.beans.config.KronosCommonStrategy
import com.kotlinorm.beans.dsl.Field
Kronos.logicDeleteStrategy = KronosCommonStrategy(enabled = true, field = Field("deleted"))Delete writes the delete marker
When logical delete is enabled, delete().execute() generates an UPDATE that writes the deleted value. The generated condition also keeps already deleted rows out of the target set.
kotlin
User(id = 1)
.delete()
.by { it.id }
.execute()Mysql
UPDATE `user`
SET `deleted` = :deletedNew
WHERE `id` = :id
AND `deleted` = 0params
id = 1
deletedNew = 1Use .logic(false) for the current delete when the operation must generate a physical DELETE.
kotlin
User(id = 1)
.delete()
.logic(false)
.by { it.id }
.execute()Mysql
DELETE
FROM `user`
WHERE `id` = :idSelect and update ignore deleted rows
Select and update statements add the active-row condition for a KPojo with logical delete enabled.
kotlin
User()
.select { [it.id, it.name] }
.toMapList()
User(id = 1)
.update()
.set { it.name = "Kronos" }
.by { it.id }
.execute()select
SELECT `id`, `name`
FROM `user`
WHERE `deleted` = 0update
UPDATE `user`
SET `name` = :nameNew
WHERE `id` = :id
AND `deleted` = 0Insert and upsert maintain the marker
Insert initializes the logical delete field with the active value. When match-field upsert finds a logically deleted row, Kronos updates that row and restores the logical delete field to the active value. onConflict() upsert also includes that field in the inserted columns when the strategy is active, and writes the active value during conflict update.
kotlin
User(name = "Kronos")
.insert()
.execute()Mysql
INSERT INTO `user` (`name`, `deleted`)
VALUES (:name, :deleted)params
name = "Kronos"
deleted = 0kotlin
User(id = 1, name = "Kronos")
.upsert { it.name }
.on { it.id }
.execute()update
UPDATE `user`
SET `name` = :nameNew,
`deleted` = :deletedNew
WHERE `id` = :idDataGuard boundary
Logical delete changes a delete into an update statement. If no user condition is provided, the generated statement can still target every active row.
kotlin
User()
.delete()
.execute()Mysql
UPDATE `user`
SET `deleted` = :deletedNew
WHERE `deleted` = 0Enable 📚DataGuard when the application should reject full-table writes. See 📚Delete and 📚Update for condition APIs.