DELETE Statements
Remove records from your database safely and precisely.
Basic DELETE
basic.ts
// Delete by ID
cook`yeet:users sus:id=1`
// → DELETE FROM users WHERE id = $1
// Delete by condition
cook`yeet:sessions sus:expired=true`
// → DELETE FROM sessions WHERE expired = $1With RETURNING
returning.ts
// Return deleted row
cook`yeet:users sus:id=1 flex:*`
// → DELETE FROM users WHERE id = $1 RETURNING *
// Return specific columns
cook`yeet:users sus:id=1 flex:id,email`
// → DELETE FROM users WHERE id = $1 RETURNING id, emailConditional Deletes
conditional.ts
// Multiple conditions
cook`yeet:posts sus:status=draft sus:created_at<2024-01-01`
// → DELETE FROM posts WHERE status = $1 AND created_at < $2
// OR conditions
cook`yeet:notifications sus:read=true|created_at<2024-01-01`
// → DELETE FROM notifications WHERE read = $1 OR created_at < $2
// Using IN
cook`yeet:users sus:id.in(1,2,3,4,5)`
// → DELETE FROM users WHERE id IN ($1, $2, $3, $4, $5)Soft Deletes
Instead of hard deletes, mark records as deleted:
soft-delete.ts
// Configure soft deletes in schema
const schema = defineSchema({
users: {
// ... columns
deleted_at: 'timestamp?'
}
}, {
softDelete: {
column: 'deleted_at',
tables: ['users', 'posts']
}
});
// This becomes an UPDATE instead of DELETE
cook`yeet:users sus:id=1`
// → UPDATE users SET deleted_at = NOW() WHERE id = $1
// Force hard delete when needed
cook`yeet:users sus:id=1 hard:true`
// → DELETE FROM users WHERE id = $1Cascade Deletes
cascade.ts
// With relations defined, cascade deletes child records
await db.delete(
cook`yeet:users sus:id=1`,
{ cascade: ['posts', 'comments'] }
);
// Deletes user and all their posts and commentsDanger Zone
DELETE without WHERE will remove all rows. genaql requires explicit confirmation or can be configured to always require WHERE clauses.
Best Practice
Use soft deletes for user data, transactions within deletes for consistency, and always test delete queries with SELECT first.