Example
Raw SQL, Templates, and Recipes
Quarry keeps the escape hatch visible. Codex adds a small registry for reusable raw SQL templates and typed recipe wrappers when the same shape shows up again.
Raw fragments
q := qq.Select(
"id",
"email",
quarry.Raw("COUNT(*) FILTER (WHERE status = ?)", "active"),
).
From("users").
Where(quarry.Raw("created_at >= ?", since))
Placeholder rewriting still happens
Raw fragments keep the raw SQL visible, but
? placeholders still become
dialect tokens and the scanner ignores quoted text, comments, and dollar-quoted
bodies. Raw fragments are trusted SQL text; they are not a sanitizer for user input.
Named templates
store := codex.NewStore()
store.MustAdd("users.by_email", `
SELECT id, email, status
FROM users
WHERE tenant_id = :tenant_id
AND email = :email
`)
template, ok := store.Get("users.by_email")
if !ok {
panic("missing query")
}
bound := template.With(qq).BindMap(map[string]any{
"tenant_id": 42,
"email": "ada@example.com",
})
Strict mode
If you want unused named arguments rejected, set strict mode on the store before you
add the query.
Recipes
type UserSearchParams struct {
TenantID int
Query string
Status *string
}
recipe := codex.NewRecipe(func(qq *quarry.Quarry, p UserSearchParams) quarry.SQLer {
return qq.Select("id", "email", "status").
From("users").
Where(
quarry.Eq("tenant_id", p.TenantID),
quarry.OptionalILike("email", p.Query),
quarry.OptionalEq("status", p.Status),
)
})
if err := store.AddRecipe("users.search", recipe); err != nil {
panic(err)
}
q, err := store.MustRecipe("users.search").Build(qq, UserSearchParams{
TenantID: 42,
Query: "%bob%",
})
if err != nil {
panic(err)
}
What this section is for
It shows how a recipe stays close to raw SQL while still returning a Quarry query
that the rest of the code can render or execute.
When the raw query is still the right tool
- Window functions that are easier to read directly.
- Vendor-specific operators that Quarry should not pretend to understand.
- Existing SQL that you want to keep verbatim while only changing the bindings.
- Queries that are reused often enough to deserve a stable name in the registry.
Struct bindings and strict mode
The store can reject unused named arguments, and BindStruct maps fields
using the same tag rules as the scan layer.
store := codex.NewStore().SetStrict(true)
store.MustAdd("users.search", `
SELECT id, email, status
FROM users
WHERE tenant_id = :tenant_id
AND status = :status
`)
template, ok := store.Get("users.search")
if !ok {
panic("missing template")
}
bound := template.With(qq).BindStruct(struct {
TenantID int `db:"tenant_id"`
Status string `db:"status"`
}{
TenantID: 42,
Status: "active",
})