Soft Delete
Annotate a deletedAt field with @softDelete and SlintORM automatically injects WHERE deletedAt IS NULL on every query for that model. Calling .delete() sets the timestamp instead of removing the row.
Model setup
// Mark deletedAt with @softDelete
interface User {
id: number;
email: string;
name: string;
// @softDelete
deletedAt: string; // added automatically to the table
}
// Tables without @softDelete are unaffected — no extra columnAuto-filter on all queries
// Default behavior: WHERE deletedAt IS NULL is injected on every query
const users = await User.getAll();
// SELECT * FROM users WHERE deletedAt IS NULL
const user = await User.get({ email: 'joe@example.com' });
// WHERE email = 'joe@example.com' AND deletedAt IS NULLSoft delete operation
// .delete() on a soft-delete model sets deletedAt, not removes the row
await User.delete({ id: 42 });
// UPDATE users SET deletedAt = '2024-01-15T10:30:00Z' WHERE id = 42
// The row is now invisible to all standard queries
const user = await User.get({ id: 42 }); // nullwithTrashed
Access via model.softDelete() which returns a SoftDeleteQueryBuilder<T>.
// .withTrashed() — include soft-deleted rows
const allUsers = await User.softDelete()
.withTrashed()
.get();
// SELECT * FROM users (no deletedAt filter)
// Combine with other clauses
const suspendedAdmins = await User.softDelete()
.withTrashed()
.where('role', '=', 'admin')
.get();onlyTrashed
// .onlyTrashed() — return only soft-deleted rows
const deleted = await User.softDelete()
.onlyTrashed()
.get();
// SELECT * FROM users WHERE deletedAt IS NOT NULLrestore
// .restore(filter) — un-delete: sets deletedAt = NULL
await User.restore({ id: 42 });
// UPDATE users SET deletedAt = NULL WHERE id = 42
// User is now visible in standard queries again
const user = await User.get({ id: 42 }); // foundHard delete note
// To permanently remove a soft-delete row,
// use the query builder with whereRaw to bypass the auto-filter
await User.softDelete()
.withTrashed()
.where('id', '=', 42)
// No direct hardDelete method — use deleteMany after withTrashed
// or use orm.adapter.exec() for raw DELETEClean tables stay clean
The deletedAt column is only added to tables whose model has a field annotated with @softDelete. Models without this annotation are not affected in any way. Migration is non-destructive: existing data is preserved.