FilterGroups instead of writing the boolean logic by hand.
You’ll end up with. A working pattern for three increasingly expressive filter shapes plus an order_by / paginate recipe you can drop straight into a real query.
The mental model
A filter is groups of conditions:- Conditions inside one
FilterGroupshare an operator —AND(default) orOR. - The top-level
CompoundFilterjoins those groups together with its own operator — alsoAND(default) orOR.
(region == "EU") AND (priority > 2 OR status == "closed") is naturally two groups: one with the region condition, one with the priority/status conditions joined by OR. The compound filter joins those two groups with AND.
When the whole filter is a single AND or single OR, use CompoundFilter.of(...) — it wraps your conditions in a single group for you.
Setup
Recipe 1 — all conditions must match (AND inside a group)
“European vendors that are still open.” Conditions inside a single group default to AND, soCompoundFilter.of(...) is enough:
Recipe 2 — any condition matches (OR inside a group)
“Vendors in EU or US.” Same single-group shape, but flip the group operator toOR:
TableFilterOperator.IS_IN — but the OR shape generalises when the two conditions are on different columns.
Recipe 3 — mix AND and OR with two groups
“European vendors that are either high-priority or already closed.” Two clauses, withOR inside one and AND between groups:
Order and paginate the result
order_by and paginate chain onto any CompoundFilter. They return a new filter (the dataclass is frozen), so call them on the result of .of(...) or the constructor:
order_by is chainable for multi-key sorting — call it once per key, in priority order:
scroll(...) if you have more rows than fit in one read_rows page.
Cleanup
See also
Common filter recipes
One snippet per
TableFilterOperator, grouped by use case.CompoundFilter reference
Top-level shape and builder methods.
Rows and filters
Filters in context with insert / update / delete / scroll.
