Dynamic Filters
Quarry optional predicates disappear when their values are absent, so one query can handle many request shapes without special-case branching.
Optional filters
Optional helpers treat empty inputs as omissions. That keeps the query shape stable while letting callers pass zero values, nil pointers, or empty slices.
q := qq.Select("*").From("users").Where(
quarry.Eq("tenant_id", 42),
quarry.OptionalEq("status", nil),
quarry.OptionalILike("email", ""),
)
SELECT * FROM users WHERE tenant_id = $1
[]any{42}
status := "active"
q := qq.Select("*").From("users").Where(
quarry.Eq("tenant_id", 42),
quarry.OptionalEq("status", &status),
quarry.OptionalILike("email", "%bob%"),
)
SELECT * FROM users WHERE tenant_id = $1 AND status = $2 AND email ILIKE $3
[]any{42, "active", "%bob%"}
Grouped predicates
q := qq.Select("*").From("users").Where(
quarry.Eq("tenant_id", 42),
quarry.Or(
quarry.OptionalILike("email", "%bob%"),
quarry.OptionalILike("name", "%bob%"),
),
quarry.OptionalEq("status", nil),
)
Sorting and paging
Safe sorting
OrderBySafe and OrderBySafeDefault only accept fragments
from a trusted lookup table.
Paging helpers
Page, LimitDefault, and OffsetDefault
keep request pagination readable.
q := qq.Select("id", "email").
From("users").
OrderBySafeDefault("newest", quarry.SortMap{
"newest": "created_at DESC",
"email": "email ASC",
}, "newest").
Page(1, 50)
Partial updates
q := qq.Update("users").
SetOptional("name", params.Name).
SetOptional("email", params.Email).
SetIf(params.Enabled != nil, "enabled", *params.Enabled).
Where(quarry.Eq("id", params.ID))
Raw SQL escape hatch
Raw SQL stays available when the query is clearer by hand. Values still bind safely.
q := qq.Select(quarry.Raw("COUNT(*) FILTER (WHERE status = ?)", "active")).
From("users").
Where(quarry.Raw("created_at >= ?", since))