Query API¶
Complete reference for the Query Builder API.
Query¶
Query.where accepts either a QueryNode (the operator and col() paths) or a lambda predicate of shape Callable[[QueryProxy[TModel]], QueryNode]. See Typed Query Predicates for a full treatment of the three predicate styles.
Query
¶
Bases: Generic[T]
Build and execute fluent ORM queries.
Attributes:
| Name | Type | Description |
|---|---|---|
model_cls |
Model class used to hydrate results. |
|
where_clause |
list[QueryNode]
|
Accumulated filter nodes for the query. |
order_by_clause |
list[dict[str, str]]
|
Sort definitions sent to the Rust core. |
Functions¶
where(node)
¶
Add a filter condition to the query.
Accepts either a :class:QueryNode (built directly with operator
syntax or with :func:ferro.query.col) or a lambda predicate of
shape Callable[[QueryProxy[T]], QueryNode]. The lambda receives
a fresh :class:QueryProxy whose attributes return
:class:FieldProxy instances, so lambda t: t.archived == False
builds a comparison without static-typing friction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
node
|
QueryNode | Predicate[T]
|
A |
required |
Returns:
| Type | Description |
|---|---|
Query[T]
|
The current Query instance for chaining. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
Examples:
order_by(field, direction='asc')
¶
Add an ordering clause to the query
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field
|
Any
|
The field to order by (e.g., User.username). |
required |
direction
|
str
|
The direction of the sort ("asc" or "desc"). |
'asc'
|
Returns:
| Type | Description |
|---|---|
Query[T]
|
The current Query instance for chaining. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If direction is not "asc" or "desc". |
Examples:
limit(value)
¶
Limit the number of records returned
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
int
|
The maximum number of records to return. |
required |
Returns:
| Type | Description |
|---|---|
Query[T]
|
The current Query instance for chaining. |
Examples:
offset(value)
¶
Skip a specific number of records
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
int
|
The number of records to skip. |
required |
Returns:
| Type | Description |
|---|---|
Query[T]
|
The current Query instance for chaining. |
Examples:
all()
async
¶
first()
async
¶
count()
async
¶
exists()
async
¶
update(**fields)
async
¶
Update all records matching the current query
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**fields
|
Field names and values to update. |
{}
|
Returns:
| Type | Description |
|---|---|
int
|
The number of records updated. |
Examples:
delete()
async
¶
Relation¶
Relation is the lazy collection-relationship subclass of Query returned by BackRef and ManyToMany fields. It accepts the same three predicate styles on where.
Relation
¶
Bases: Query[T]
Represent lazy collection relationship queries with typing support
Examples:
>>> class User(Model):
... id: Annotated[int, FerroField(primary_key=True)]
... name: str
... posts: Relation[list["Post"]] = BackRef()
col¶
Runtime-identity wrapper that statically narrows a model class attribute back to FieldProxy[T]. Use it when a single attribute on an existing chain trips your type checker; for new code prefer the lambda predicate style.
col(value)
¶
Treat a model class attribute as a typed query column.
At runtime Ferro's metaclass replaces Model.field with a
:class:FieldProxy, so Model.field is already a FieldProxy when
accessed on the class. Static type checkers, however, see the field's
Pydantic-annotated type (bool, int, ...). That makes expressions
like Model.archived == False resolve to bool statically, even
though the runtime value is a QueryNode.
col() is runtime-identity for FieldProxy inputs and statically
narrows the return type to FieldProxy[T], so col(Model.archived) ==
False type-checks as QueryNode. Use it when a single attribute
trips your type checker; for new code, prefer the lambda predicate API
on :meth:Query.where.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
TField
|
A model class attribute (already a |
required |
Returns:
| Type | Description |
|---|---|
FieldProxy[TField]
|
The same object, statically typed as |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
Examples:
FieldProxy¶
The typed proxy installed by Ferro's metaclass on every model class field. Generic over the column's Python type; operator overloads accept T | FieldProxy[T] and return QueryNode.
FieldProxy
¶
Bases: Generic[TField]
Capture field comparisons and build query nodes
FieldProxy is generic over the column's Python type so that operator
overloads carry that type into static analysis. At runtime the type
parameter is erased and the proxy works identically for any column type.
Attributes:
| Name | Type | Description |
|---|---|---|
column |
Database column name associated with the model field. |
Examples:
Functions¶
in_(other)
¶
Build an IN comparison node from an iterable
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other
|
list[TField] | tuple[TField, ...] | set[TField]
|
Collection of values to match against the field. |
required |
Returns:
| Type | Description |
|---|---|
QueryNode
|
A node using the SQL |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
Examples:
like(pattern)
¶
Build a LIKE comparison node
The self: FieldProxy[str] annotation prevents type checkers from
accepting .like(...) on non-string columns; at runtime the method
is available on any FieldProxy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pattern
|
str
|
SQL LIKE pattern such as |
required |
Returns:
| Type | Description |
|---|---|
QueryNode
|
A node using the SQL |
Examples:
QueryProxy¶
The attribute proxy passed to lambda predicates. Each attribute access returns a fresh FieldProxy for the accessed name.
QueryProxy
¶
Bases: Generic[TModel]
Lazy attribute proxy used by lambda predicates passed to Query.where.
A fresh QueryProxy is constructed each time a lambda predicate is
evaluated. Any attribute access returns a :class:FieldProxy for the
accessed name, so lambda t: t.archived == False builds a
:class:QueryNode without ever asking the model class what type
archived is. The TModel type parameter exists so user-supplied
lambdas can narrow t to a specific model in static analysis; the
proxy itself ignores the parameter at runtime.
The proxy attribute return type is intentionally FieldProxy[Any] for
now — wiring per-field types through a lambda parameter requires
@dataclass_transform plumbing on the metaclass, which is outside this
feature's scope.
Examples:
QueryNode¶
The serializable AST node produced by every predicate style. You normally do not construct these directly.
QueryNode
¶
Represent a node in the query expression tree
Attributes:
| Name | Type | Description |
|---|---|---|
column |
Column name for leaf nodes. |
|
operator |
Comparison or logical operator. |
|
value |
Right-hand value for leaf comparisons. |
|
left |
Left child node for compound expressions. |
|
right |
Right child node for compound expressions. |
|
is_compound |
Flag indicating whether the node combines two child nodes. |
Examples:
>>> active_filter = User.active == True
>>> admin_filter = User.role == "admin"
>>> expr = active_filter & admin_filter
>>> isinstance(expr, QueryNode)
True
Predicate¶
Type alias for lambda predicates accepted by Query.where, Relation.where, and Model.where.