Skip to main content
Version: 1.1.0

Querying API Reference

Reference for read execution methods on *quark.Query[T].

First​

First() (T, error)​

Returns the first matching row or quark.ErrNotFound.

user, err := quark.For[User](ctx, client).
Where("active", "=", true).
OrderBy("created_at", "DESC").
First()

Behavior:

CaseReturn
Row exists(entity, nil)
No row(zero, quark.ErrNotFound)
Query or scan error(zero, error)

First sets Limit(1) internally.

Find​

Find(id any) (T, error)​

Finds one row by simple primary key.

user, err := quark.For[User](ctx, client).Find(42)

Find is for single-column primary keys. For composite primary keys, use Where(...).First():

item, err := quark.For[OrderItem](ctx, client).
Where("order_id", "=", orderID).
Where("product_id", "=", productID).
First()

Soft-delete filters and tenant filters still apply.

List​

List() ([]T, error)​

Executes the select and scans matching rows into []T.

users, err := quark.For[User](ctx, client).
Where("active", "=", true).
OrderBy("name", "ASC").
Limit(100).
List()

If no explicit limit has been set, List applies a safe default limit of 100 and logs a warning. Use Iter or Cursor for intentionally unbounded reads.

List respects:

FeatureBehavior
Soft deletesAdds deleted_at IS NULL unless Unscoped() is set.
Tenant routerApplies schema or row-level isolation.
CacheReads and writes cache entries when .Cache(...) is enabled.
PreloadLoads requested relations after parent rows are scanned.
MiddlewareExecutes through registered query middleware.
ObserversEmits a QueryEvent after execution.

Count​

Count() (int64, error)​

Counts matching rows.

count, err := quark.For[User](ctx, client).
Where("active", "=", true).
Count()

Count includes Where, joins, soft-delete filters, and tenant filters. It does not apply Limit or Offset.

Aggregates​

Sum(column string) (float64, error)​

total, err := quark.For[Order](ctx, client).
Where("status", "=", "paid").
Sum("amount")

Avg(column string) (float64, error)​

avg, err := quark.For[Order](ctx, client).Avg("amount")

Min(column string) (float64, error)​

min, err := quark.For[Product](ctx, client).
Where("stock", ">", 0).
Min("price")

Max(column string) (float64, error)​

max, err := quark.For[Product](ctx, client).
Where("stock", ">", 0).
Max("price")

Aggregate column names are validated as identifiers. The helpers return 0 when the database aggregate result is NULL.

Paginate​

Paginate(pageSize, page int) (*Page[T], error)​

Runs a count query and a limited select.

page, err := quark.For[User](ctx, client).
Where("active", "=", true).
OrderBy("id", "ASC").
Paginate(20, 0)

fmt.Println(page.Items)
fmt.Println(page.Total)
fmt.Println(page.TotalPages)

page is zero-indexed. Negative pages are treated as 0. A non-positive pageSize defaults to 100.

type Page[T any] struct {
Items []T
Total int64
Page int
PageSize int
TotalPages int64
}

Cursor​

Cursor() (*Cursor[T], error)​

Returns a type-safe cursor over sql.Rows.

cursor, err := quark.For[LogEntry](ctx, client).
Where("level", "=", "error").
OrderBy("id", "ASC").
Cursor()
if err != nil {
return err
}
defer cursor.Close()

for cursor.Next() {
var entry LogEntry
if err := cursor.Scan(&entry); err != nil {
return err
}
process(entry)
}

return cursor.Err()

Cursor methods:

MethodDescription
Next() boolAdvances to the next row.
Scan(dest *T) errorScans the current row into dest.
Close() errorCloses rows, cancels the query context, and emits an observer event.
Err() errorReturns the underlying row iteration error.

Always call Close.

Iter​

Iter(fn func(T) error) error​

Streams rows through a callback.

err := quark.For[Event](ctx, client).
Where("processed", "=", false).
OrderBy("id", "ASC").
Iter(func(event Event) error {
if err := processEvent(event); err != nil {
return err
}
return nil
})

Iteration stops on the first callback error, scan error, query error, or rows error.

Scanning Rules​

Rows are scanned by matching result columns to model fields:

Match sourceNotes
db tagFast path through cached metadata.
snake-cased field nameFallback for columns without a metadata hit.
exact field nameFallback for matching driver column names.

Unknown result columns are discarded. For custom projections, define a dedicated read model with matching db tags or use raw SQL and manual scanning.

time.Time and *time.Time fields include scanner wrappers for drivers that return datetime values as strings or byte slices.