DELETE
db.delete(table) builds a DELETE FROM query. It supports multi-table deletes via USING, CTEs, a WHERE clause, an optional RETURNING clause, and a runtime override for WHERE.
const { query, args } = db.delete('user')
.where({ id: 99 })
.prepare()();DELETE FROM user
WHERE (id = $1).where()
Same syntax as SELECT. See the WHERE reference in the main README.
db.delete('post')
.where({ published: false, '<=:views': 0 })
.prepare()()DELETE FROM post
WHERE (published = $1 AND views <= $2)Column-to-column comparisons with col():
import { col } from 'helice';
db.delete('post')
.where({ 'post.author_id': col('user.id') })
.prepare()().using() — multi-table DELETE
PostgreSQL supports DELETE … USING to filter rows by joining another table. Pass the table names to .using(), then reference them in .where().
import { col } from 'helice';
db.delete('post')
.using(['user'])
.where({ 'post.author_id': col('user.id'), 'user.active': false })
.prepare()()DELETE FROM post
USING user
WHERE (post.author_id = user.id AND user.active = $1).with() — CTEs
Prepends a WITH clause, useful when the set of rows to delete is derived from a subquery.
db.delete('post')
.with('stale_authors', db.select('user').where({ active: false }))
.using(['stale_authors'])
.where({ 'post.author_id': col('stale_authors.id') })
.prepare()()WITH stale_authors AS (
SELECT *
FROM user
WHERE (active = $1)
)
DELETE FROM post
USING stale_authors
WHERE (post.author_id = stale_authors.id)Parameter numbering across CTEs and the main query is handled automatically.
Runtime CTE args
Pass a prepare options object as the third argument to .with() to enable runtime overrides inside the CTE. The CTE's args are passed under the alias key at call time:
const q = db.delete('post')
.with(
'target_authors',
db.select('user').where({ active: true }),
{ where: true }
)
.using(['target_authors'])
.where({ 'post.author_id': col('target_authors.id') })
.prepare();
q({ target_authors: { where: { '~~:name': 'Alice%' } } }).in() / .notIn()
Adds a col IN (subquery) or col NOT IN (subquery) condition.
// Delete posts by inactive users
db.delete('post')
.in('author_id', db.select('user').field(['id']).where({ active: false }))
.prepare()()
// WHERE (author_id IN (SELECT id FROM user WHERE (active = $1)))
// Delete orphaned posts (author no longer exists)
db.delete('post')
.notIn('author_id', db.select('user').field(['id']))
.prepare()()
// WHERE (author_id NOT IN (SELECT id FROM user)).returning()
Appends RETURNING to the query:
db.delete('post')
.where({ published: false })
.returning({ postId: 'id', postTitle: 'title' })
.prepare()()DELETE FROM post
WHERE (published = $1)
RETURNING id AS postId, title AS postTitle.build() / .execute()
const { query, args } = db.delete('user').where({ id: 99 }).build();
await db.delete('user').where({ id: 99 })
.execute((q, a) => pgClient.query(q, a));Both use the static WHERE only. For runtime where, use .prepare().
.prepare() — runtime options
| Option | Type | Behaviour |
|---|---|---|
where |
true |
Runtime WHERE merged AND with static WHERE |
where |
{ [table]: true | string[] } |
Same, restricted to specific tables/columns |
Examples
// Runtime WHERE merged AND with a static condition
const deletePostsBy = db.delete('post')
.where({ author_id: 3 })
.prepare({ where: true });
deletePostsBy({ where: { published: false } })
// WHERE (author_id = $1 AND published = $2)
// Restricted runtime WHERE — only 'views' column allowed
const deleteStale = db.delete('post')
.where({ published: false })
.prepare({ where: { post: ['views'] } });
deleteStale({ where: { '<=:views': 0 } })
// WHERE (published = $1 AND views <= $2)
// TypeScript rejects any column outside ['views']