Example
Patch/Update Examples
A patch endpoint usually needs three things: ignore missing fields, preserve explicit zero values, and return the row that actually changed. Quarry keeps those cases explicit instead of hiding them in string concatenation.
Profile patch endpoint
type ProfilePatch struct {
ID int
DisplayName *string
Email *string
Bio *string
Enabled *bool
}
q := qq.Update("profiles").
SetOptional("display_name", patch.DisplayName).
SetOptional("email", patch.Email).
SetOptional("bio", patch.Bio).
SetIf(patch.Enabled != nil, "enabled", *patch.Enabled).
Where(quarry.Eq("id", patch.ID)).
Returning("id", "display_name", "email", "bio", "enabled")
Why SetOptional matters
A nil pointer means “do not touch this field.” A pointer to an empty string still
becomes a real update if that is what the caller asked for.
Map-driven changes
Sometimes the fields come from a map that already has stable keys. SetMap
keeps the column order deterministic, so review diffs stay readable.
changes := map[string]any{
"display_name": "Alice Wu",
"timezone": "UTC",
"theme": "dark",
}
q := qq.Update("profiles").
SetMap(changes).
Where(quarry.Eq("id", 42))
UPDATE profiles
SET display_name = $1, theme = $2, timezone = $3
WHERE id = $4
Returning the changed row
updated, err := scan.One[Profile](ctx, db,
qq.Update("profiles").
SetOptional("bio", patch.Bio).
SetIf(patch.Enabled != nil, "enabled", *patch.Enabled).
Where(quarry.Eq("id", patch.ID)).
Returning("id", "display_name", "email", "bio", "enabled"),
)
Dialect note
Postgres and SQLite can return rows directly. MySQL does not, so the builder returns a
clear unsupported-feature error instead of pretending otherwise.
Bulk writes and soft deletes
Bulk insert
q := qq.InsertInto("audit_log").
Columns("actor_id", "action", "created_at").
Rows(
[]any{42, "profile.updated", time.Now()},
[]any{42, "profile.viewed", time.Now()},
)
Soft delete
q := qq.Update("profiles").
Set("deleted_at", time.Now()).
SetOptional("deleted_reason", patch.Reason).
Where(quarry.Eq("id", patch.ID))