ftmq.Query
See the query guide for a narrative introduction.
A filter over FtM entities, built from composable M / P / G nodes.
Examples:
from ftmq import Query, M, P, G
q = Query().where(M(schema="Person"), P(name__ilike="jane%"))
q = q.where(G(countries="de") | G(countries="at"))
q = q.order_by("name")[:10]
Source code in ftmq/query/main.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 | |
context
property
The current context filters (the C family, e.g. origin)
countries
property
The current filtered countries
dataset_names
property
The names of the current filtered datasets
datasets
property
The current dataset filters
groups
property
The current property groups lookup filters
ids
property
The current id filters
limit
property
The current limit (inferred from a slice)
offset
property
The current offset (inferred from a slice)
A start-less slice (q[:10]) reports offset 0, so it serializes and
round-trips identically to q[0:10].
properties
property
The current property lookup filters
schemata
property
The current schema filters
schemata_names
property
The names of the current filtered schemas
Exact schema leaves contribute their name; schemata (is-a) leaves
expand to the schema plus its non-abstract descendants.
sql
property
__bool__()
Detect if any filter, ordering or slicing is defined
Examples:
__getitem__(value)
Implement list-like slicing. No negative values allowed.
Examples:
Returns:
| Type | Description |
|---|---|
Self
|
The updated |
Source code in ftmq/query/main.py
__hash__()
Generate a unique key of the current state, useful for caching.
Like any Python object this is a within-process hash (not stable
across processes); hash_data normalizes ordering so equal queries
hash equal.
Source code in ftmq/query/main.py
aggregate(*nodes)
Add aggregation projections to the query.
Example
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*nodes
|
A
|
|
()
|
Returns:
| Type | Description |
|---|---|
Self
|
The updated |
Source code in ftmq/query/main.py
apply(entity)
apply_iter(entities)
Apply the current Query instance to a generator of entities and return
a generator of filtered entities
Example
Yields:
| Type | Description |
|---|---|
EntityProxies
|
A generator of |
Source code in ftmq/query/main.py
compile(source=None)
Compile this query to a SQLAlchemy Select of statements against a
SqlSource (a store's table descriptor).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
'SqlSource | None'
|
The SQL source to compile against (default: the base nomenklatura statement table). |
None
|
Returns:
| Type | Description |
|---|---|
'Select[Any]'
|
The statements |
Source code in ftmq/query/main.py
from_dict(data)
classmethod
Rebuild a Query from its to_dict output.
Source code in ftmq/query/main.py
from_params(args)
classmethod
Build a Query from an Aleph-style param dict / MultiDict.
Source code in ftmq/query/main.py
from_rql(value)
classmethod
Build a Query from an RQL string.
Unlike the flat Aleph grammar, RQL expresses arbitrary & | ~ nesting,
e.g. and(eq(schema,Person),or(eq(properties.name,jane),eq(countries,de))),
and carries aggregations via its sum / aggregate(...) operators.
Source code in ftmq/query/main.py
from_string(value)
classmethod
get_aggregator()
Build an in-memory Aggregator from the query's aggregation specs.
Returns:
| Type | Description |
|---|---|
Aggregator
|
A fresh accumulator over this query's aggregations. |
order_by(value, *, ascending=True)
Set the sorting (a single field; the SQL adapter never supported more).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str
|
The field to order by; a leading |
required |
ascending
|
bool
|
Ascending or descending |
True
|
Returns:
| Type | Description |
|---|---|
Self
|
The updated |
Source code in ftmq/query/main.py
to_dict()
Lossless nested-tree representation of the current object.
Example
Source code in ftmq/query/main.py
to_params()
Project to an Aleph-style filter param dict (filter: / exclude: /
empty: keys, metric: / facet aggregation keys, plus sort /
limit / offset).
Raises QueryError for queries outside the flat Aleph-expressible
subset (cross-field OR, negated groups).
Source code in ftmq/query/main.py
to_rql()
Serialize the filter tree and aggregations to an RQL string.
RQL is the only string surface that preserves arbitrary & | ~ nesting
(unlike the flat Aleph params) and carries aggregations losslessly, so it
is the way to hand a full query to another HTTP-like connector. Raises
QueryError for a comparator with no RQL equivalent (null,
startswith, endswith, ...).
Source code in ftmq/query/main.py
to_string()
Project to an Aleph URL query string, e.g.
filter:properties.name=Jane&filter:schemata=LegalEntity.
where(*nodes)
AND another set of M / P / G nodes into the current Query.
Example
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*nodes
|
Expr
|
|
()
|
Returns:
| Type | Description |
|---|---|
Self
|
The updated |
Source code in ftmq/query/main.py
Query nodes
The composable filter-node constructors: M (meta), P (property), G (property-type group) and C (context). A is the aggregation-projection node (see Aggregations below).
Bases: _FamilyExpr
Meta fields: dataset, schema, schemata, id, ... - M(schema="Person")
as a condition, M("dataset") as a reference.
Source code in ftmq/query/nodes.py
Bases: _FamilyExpr
A specific FtM property: P(name="Jane", amountEur__gte=1000) as a
condition, P("amountEur") as a reference.
Source code in ftmq/query/nodes.py
Bases: _FamilyExpr
A property-type group: G(countries="de") as a condition,
G("countries") as a reference.
Source code in ftmq/query/nodes.py
Bases: _FamilyExpr
A context / storage column: C(origin="crawl") as a condition,
C("origin") as a reference.
Source code in ftmq/query/nodes.py
An aggregation projection node: A(sum=P("amountEur"), by=P("beneficiary")).
Each keyword is an aggregation function (min, max, sum, avg,
count) whose value is the field reference (or references) to aggregate;
by= groups by one or more references. Fields are addressed with the same
M / P / G / C markers the filter families use, called with a bare
field name (plus Year()), so an aggregation says which family it means
instead of leaving it to be guessed from the name. Unlike the filter nodes,
A is not a boolean leaf - it does not compose with & | ~; pass it to
Query.aggregate.
Examples:
A(sum=P("amountEur"), by=P("beneficiary"))
A(count=M("id"), by=[G("countries"), Year()])
A(sum=[P("amountEur"), P("amount")])
Source code in ftmq/query/aggregations.py
Expression tree
A boolean node: a connector (AND/OR), an optional negation, and a
list of children (nested Expr nodes and/or Leaf conditions).
Source code in ftmq/query/nodes.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | |
apply(entity)
Evaluate the boolean expression against an entity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entity
|
EntityProxy
|
The entity to test. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
negated) tree of conditions. |
Source code in ftmq/query/nodes.py
from_dict(data)
classmethod
Rebuild a tree from its to_dict form.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict[str, Any]
|
The nested mapping to deserialize. |
required |
Returns:
| Type | Description |
|---|---|
'Expr'
|
The reconstructed expression. |
Source code in ftmq/query/nodes.py
iter_leaves(cls=None)
Walk the tree and yield its leaf conditions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cls
|
type | None
|
Optionally restrict to leaves of this class. |
None
|
Yields:
| Type | Description |
|---|---|
Leaf
|
Each matching leaf, depth-first. |
Source code in ftmq/query/nodes.py
to_dict()
Serialize the tree to a nested, canonically-ordered dict.
Nested nodes that share the connector and are not negated are flattened
(associativity) and children are sorted, so structurally-equivalent
trees (e.g. built by different where() orderings) serialize
identically and hash equal.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
A |
dict[str, Any]
|
Source code in ftmq/query/nodes.py
Combine a series of nodes with a single connector, skipping empties.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*nodes
|
Expr
|
The |
()
|
connector
|
str
|
|
AND
|
Returns:
| Type | Description |
|---|---|
Expr | None
|
The combined expression, or |
Source code in ftmq/query/nodes.py
Field references
A field without a value: what an aggregation projects over, and what a leaf carries besides its comparator. Built by the same family constructors, called with a bare field name (P("amountEur")).
Field references: a leaf without a value.
A Ref names where to read - a followthemoney
property, a property-type group, a meta column, a context column - without
saying what to match. It is what a filter leaf carries besides its comparator
and value, and it is what an aggregation
(A) projects over:
Query().where(P(amountEur__gte=1000)) # a leaf: ref + comparator + value
Query().aggregate(A(sum=P("amountEur"))) # an aggregation: just the ref
Refs are built by the same family constructors as filter leaves, called with a
positional field name instead of field=value lookups: M("dataset"),
P("amountEur"), G("countries"), C("origin"), plus Year() for the
date-derived year dimension.
Every ref knows how to read its values off an entity (used by the in-memory
evaluator, and by the filter leaves, which delegate here) and how it is spelled
on the wire (Ref.wire /
ref_from_wire). The SQL side maps refs to
columns in ftmq.query.sql, keeping sqlalchemy out of the query IR.
CanonicalIdRef
ContextRef
Bases: Ref
A context / storage column: origin, plus backend-specific columns
such as fragment, first_seen or bucket.
Source code in ftmq/query/refs.py
DatasetRef
EntityIdRef
GroupRef
Bases: Ref
A followthemoney property-type group (the prop_type column):
names, dates, countries, entities, ...
Source code in ftmq/query/refs.py
IdRef
Bases: MetaRef
The entity id. Aggregating it addresses entities, not the referent
ids in the value of a prop = "id" statement.
Source code in ftmq/query/refs.py
MetaRef
PropRef
Bases: Ref
One followthemoney property (the prop column).
Source code in ftmq/query/refs.py
Ref
A reference to one field of one family.
Subclasses set family / key and implement values(); they are built
via the M / P / G / C constructors rather than directly.
Source code in ftmq/query/refs.py
is_numeric
property
Whether the values are numbers (read through followthemoney's number parser instead of as strings).
wire
property
How this ref is spelled on a string surface (params, rql, dict keys, CLI flags): the same spelling the filter grammar uses.
SchemaRef
YearRef
Bases: Ref
The year of any date-typed value - a dimension derived from the dates
group, not a column of its own.
Source code in ftmq/query/refs.py
Year()
make_meta_ref(key)
Build a meta ref (the M family) by field name.
ref_from_wire(value)
Resolve a wire spelling back into a ref - the single place a string
becomes a field reference, used by every string surface (URL params, RQL,
to_dict keys, CLI flags).
The family is encoded in the spelling: properties.<name> for a property,
group.<name> for a property-type group, context.<name> for a context
column; a meta field (id, entity_id, canonical_id, dataset,
schema) and year are bare.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str
|
A wire key such as |
required |
Returns:
| Type | Description |
|---|---|
Ref
|
The resolved ref. |
Raises:
| Type | Description |
|---|---|
QueryError
|
If the spelling matches no field of any family. |
Source code in ftmq/query/refs.py
Leaves
Leaf conditions for the ftmq query language, split by the statement-table column they target:
- meta leaves (
M):dataset,schema(exact),schemata(is-a),id/entity_id/canonical_id. - the property leaf (
P): a specific FtM property (thepropcolumn). - the group leaf (
G): a followthemoney property-type group (theprop_typecolumn, keyed byregistry.groups:names,dates,countries,entities, ...). - the context leaf (
C): a provenance / storage column such asorigin,fragmentorfirst_seen(read fromentity.contextin-memory).
Leaf handles comparator matching and value casting; its subclasses add the
per-family entity access plus correct null (present/absent) semantics.
CanonicalIdLeaf
ContextLeaf
Bases: RefLeaf
A context field (the C family).
In-memory it reads entity.context[key] (always treated as multi-valued);
in SQL it maps to the same-named statement-table column. This is the general
form of provenance / storage fields - origin, and extra columns such as
fragment, first_seen, bucket - that are not followthemoney properties.
An entity without the key (or without a context) simply does not match.
Source code in ftmq/query/leaves.py
DatasetLeaf
EntityIdLeaf
GroupLeaf
Bases: RefLeaf
A property-type group (the prop_type column). entities is the
reverse-lookup group.
Source code in ftmq/query/leaves.py
IdLeaf
Leaf
A single condition: a comparator plus a cast value. Subclasses set
family and implement values() (the entity values to test) or override
apply().
The comparator is validated upstream by
parse_lookup; here it is a plain string.
Source code in ftmq/query/leaves.py
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | |
wire
property
How this leaf's field is spelled on a string surface (Aleph params, RQL). Ref-backed leaves defer to their ref, so a filter and an aggregation over the same field are spelled identically.
apply(entity)
Test whether the entity matches this condition.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entity
|
EntityProxy
|
The entity to test. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
for the |
Source code in ftmq/query/leaves.py
field_dict()
Serialize this leaf to a family-tagged mapping.
Returns:
| Type | Description |
|---|---|
LeafDict
|
The |
LeafDict
|
the query-tree serialization. |
Source code in ftmq/query/leaves.py
match(value)
Apply the comparator to one entity value (the in-memory match).
Source code in ftmq/query/leaves.py
values(entity)
Yield the entity values this leaf tests against.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entity
|
EntityProxy
|
The entity to read values from. |
required |
Yields:
| Type | Description |
|---|---|
str
|
The relevant string values (property values, schema name, ...). |
Source code in ftmq/query/leaves.py
LeafDict
Bases: TypedDict
Serialized form of a single Leaf condition.
Source code in ftmq/query/leaves.py
PropertyLeaf
Bases: RefLeaf
Matches a specific FtM property value (the prop column).
Source code in ftmq/query/leaves.py
RefLeaf
Bases: Leaf
A leaf whose field access is a Ref: the ref
validates the field name and reads the entity values, the leaf adds the
comparator. Aggregations project over the same refs.
Source code in ftmq/query/leaves.py
SchemaLeaf
Bases: RefLeaf
Exact schema match.
Source code in ftmq/query/leaves.py
SchemataLeaf
Bases: Leaf
is-a match: the entity's schema (or one of its ancestors) is the
queried schema, i.e. model[X] in entity.schema.schemata.
Source code in ftmq/query/leaves.py
leaf_from_dict(data)
Reconstruct a leaf from its serialized LeafDict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
LeafDict
|
The |
required |
Returns:
| Type | Description |
|---|---|
Leaf
|
The reconstructed leaf. |
Source code in ftmq/query/leaves.py
make_context_leaf(key, value)
Build a context leaf (the C family) from a lookup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
A context / column key, e.g. |
required |
value
|
Any
|
The lookup value. |
required |
Returns:
| Type | Description |
|---|---|
Leaf
|
The resolved context leaf. |
Source code in ftmq/query/leaves.py
make_group_leaf(key, value)
Build a property-type group leaf (the G family) from a lookup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
A group lookup key, e.g. |
required |
value
|
Any
|
The lookup value. |
required |
Returns:
| Type | Description |
|---|---|
Leaf
|
The resolved group leaf. |
Raises:
| Type | Description |
|---|---|
QueryError
|
If the group is not a valid |
Source code in ftmq/query/leaves.py
make_meta_leaf(key, value)
Build a meta leaf (the M family) from a lookup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
A meta lookup key, e.g. |
required |
value
|
Any
|
The lookup value. |
required |
Returns:
| Type | Description |
|---|---|
Leaf
|
The resolved meta leaf. |
Raises:
| Type | Description |
|---|---|
QueryError
|
If the field is not a known meta field. |
Source code in ftmq/query/leaves.py
make_property_leaf(key, value)
Build a property leaf (the P family) from a lookup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
A property lookup key, e.g. |
required |
value
|
Any
|
The lookup value. |
required |
Returns:
| Type | Description |
|---|---|
Leaf
|
The resolved property leaf. |
Raises:
| Type | Description |
|---|---|
QueryError
|
If the property is not a valid FtM property. |
Source code in ftmq/query/leaves.py
parse_lookup(key)
Split a field__comparator lookup key into its parts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
A lookup key such as |
required |
Returns:
| Type | Description |
|---|---|
tuple[str, str]
|
A |
Raises:
| Type | Description |
|---|---|
QueryError
|
If the comparator suffix is not a valid comparator. |
Source code in ftmq/query/leaves.py
Aleph bridge
The filter half of the Aleph URL-param grammar. Query.to_params / from_params and to_string / from_string wrap these.
The Aleph / OpenAleph URL-param grammar: a bidirectional bridge between a
Query filter tree and the filter: / exclude: / empty: param convention
used by openaleph_search.SearchQueryParser.
The filter half (the mapping between the boolean tree and the param keys)
lives here, plus the aggregation half (metric:<func>=<prop> and
facet=<field>, matching openaleph's metric aggregations). sort / limit /
offset are query-level concerns handled by Query.to_params /
Query.from_params.
The param model is flat (AND across keys, OR within a key, exclude: and
empty: for negation / absence), so:
params_to_expris total and always yields a flat AND-of-leaves.expr_to_paramsis defined on that flat subset and raisesQueryErrorfor a cross-field OR or a negated group.
aggregations_to_params(aggs)
Project aggregation specs to openaleph metric / facet params.
Each spec becomes a metric:<func>=<field> entry (the convention
openaleph_search.SearchQueryParser reads as
metrics = {func: {fields}}); grouped fields become facet=<field>
values, spelled as the filter keys are (properties.<name>,
group.<name>, context.<name>, bare meta fields and year). Facet
groups apply across all metrics - a per-metric grouping that differs
between metrics collapses to their union here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
aggs
|
set[Agg]
|
The query's aggregation specs. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, list[str]]
|
The |
Source code in ftmq/query/aleph.py
expr_to_params(expr)
Project a filter tree to Aleph filter: / exclude: / empty: params.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expr
|
Expr | None
|
The filter tree (or |
required |
Returns:
| Type | Description |
|---|---|
dict[str, list[str]]
|
The Aleph param mapping. |
Raises:
| Type | Description |
|---|---|
QueryError
|
If the tree is not Aleph-expressible (a cross-field |
Source code in ftmq/query/aleph.py
normalize_multidict(args)
Coerce params into a plain dict[str, list[str]].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
args
|
Any
|
A werkzeug |
required |
Returns:
| Type | Description |
|---|---|
dict[str, list[str]]
|
A mapping of each key to its list of string values. |
Source code in ftmq/query/aleph.py
params_to_aggregations(items)
Rebuild aggregation specs from openaleph metric: / facet params.
The inverse of aggregations_to_params:
every facet field groups every metric:<func>=<prop> (matching how
openaleph computes a metric within each facet bucket).
A facet with no metric: alongside it groups an entity count - the
idiomatic Aleph facet. Dropping it instead would discard the param in
silence and answer with empty facets.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
items
|
dict[str, list[str]]
|
A normalized param mapping. |
required |
Returns:
| Type | Description |
|---|---|
set[Agg]
|
The reconstructed aggregation specs (empty if there is neither a |
set[Agg]
|
|
Source code in ftmq/query/aleph.py
params_to_expr(items)
Build a filter tree from Aleph params (non-filter keys are ignored).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
items
|
dict[str, list[str]]
|
A normalized param mapping (see
|
required |
Returns:
| Type | Description |
|---|---|
Expr | None
|
The flat AND-of-leaves filter tree, or |
Source code in ftmq/query/aleph.py
params_to_string(params)
Render an Aleph param mapping as a URL query string.
Keys are sorted for deterministic output; value order within a key is
preserved (multi-field sort priority must not be reordered).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
params
|
dict[str, list[str]]
|
The param mapping. |
required |
Returns:
| Type | Description |
|---|---|
str
|
A |
Source code in ftmq/query/aleph.py
string_to_params(value)
Parse an Aleph URL query string into a param mapping.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str
|
A |
required |
Returns:
| Type | Description |
|---|---|
dict[str, list[str]]
|
A mapping of each key to its list of url-decoded values. |
Source code in ftmq/query/aleph.py
RQL bridge
RQL support for nested filter trees, used by Query.from_rql.
RQL (Resource Query Language) bridge.
RQL is a URL-friendly query language of nestable named operators - e.g.
and(eq(schema,Person),or(eq(properties.name,jane),eq(countries,de))) - which
maps directly onto the ftmq Expr tree (and/or/not + comparison leaves).
Unlike the flat Aleph param grammar, RQL expresses arbitrary nesting, so this is
the way to carry a full M & (P | G) tree through a single string. It also
carries aggregations: RQL's native sum / min / max / mean / count and
aggregate(...) operators map onto ftmq A nodes, side by side with the filter
under a top-level and.
Field names use the shared wire spelling (properties.<name>, group.<name>,
context.<name>, bare meta fields and year); a bare name that matches none of
those is treated as an FtM property.
expr_to_rql(expr)
Convert an Expr tree to an RQL AST ({"name": ..., "args": [...]}).
Source code in ftmq/query/rql.py
parse_rql(value)
Parse an RQL query string into a filter Expr and aggregation specs.
Filter operators (and / or / not + comparisons) build the tree; the
aggregate operators (sum / min / max / mean / count / aggregate)
build the aggregations. At the top level they sit side by side under and.
Raises:
| Type | Description |
|---|---|
QueryError
|
If the RQL uses an unsupported operator or field. |
Source code in ftmq/query/rql.py
rql_to_expr(data)
Convert a parsed RQL AST ({"name": ..., "args": [...]}) to an Expr.
Source code in ftmq/query/rql.py
to_rql(expr, aggs=())
Serialize a filter tree and aggregation specs to an RQL query string.
Filters and aggregations sit side by side under a top-level and.
Raises:
| Type | Description |
|---|---|
QueryError
|
If a filter leaf uses a comparator with no RQL equivalent
( |
Source code in ftmq/query/rql.py
Aggregations
The A projection node, the immutable Agg spec and the in-memory Aggregator. See the aggregation guide.
Aggregations for the ftmq query language.
An aggregation is a projection over the matched entities (a SELECT-list /
GROUP BY concern), not a filter predicate: the A node does not compose with
the & | ~ boolean tree the M/P/G/C filter nodes build. It is declared
with Query.aggregate, parallel to where() and
order_by().
A(sum=P("amountEur"), by=P("beneficiary")) builds one immutable
Agg spec per func=<ref> pair, where the
field is a Ref built by the same M / P / G / C
markers as a filter leaf. Aggregator is
the in-memory accumulator that runs those specs over a stream of entities; the
SQL backend reads the same specs (see ftmq.query.sql).
A
An aggregation projection node: A(sum=P("amountEur"), by=P("beneficiary")).
Each keyword is an aggregation function (min, max, sum, avg,
count) whose value is the field reference (or references) to aggregate;
by= groups by one or more references. Fields are addressed with the same
M / P / G / C markers the filter families use, called with a bare
field name (plus Year()), so an aggregation says which family it means
instead of leaving it to be guessed from the name. Unlike the filter nodes,
A is not a boolean leaf - it does not compose with & | ~; pass it to
Query.aggregate.
Examples:
A(sum=P("amountEur"), by=P("beneficiary"))
A(count=M("id"), by=[G("countries"), Year()])
A(sum=[P("amountEur"), P("amount")])
Source code in ftmq/query/aggregations.py
Agg
dataclass
An immutable aggregation spec: a function over a field reference,
optionally grouped by others. Built via the
A node or
Query.aggregate.
Source code in ftmq/query/aggregations.py
key
property
The wire spelling of the aggregated field.
Aggregator
In-memory accumulator: runs a set of Agg
specs over an entity stream.
A fresh instance per run holds all mutable state, so applying the same query twice never double-counts (the specs themselves are immutable).
Source code in ftmq/query/aggregations.py
result
property
The reduced result, keyed by the wire spelling of each field:
{func: {field: value}, "groups": {group: {func: {field: {group_value:
value}}}}} (empties removed).
apply(proxies)
Collect every entity while passing the stream through unchanged.
collect(proxy)
Accumulate one entity's values into every spec.
Source code in ftmq/query/aggregations.py
aggregations_from_dict(data)
Rebuild aggregation specs from the output of
aggregations_to_dict.
Source code in ftmq/query/aggregations.py
aggregations_to_dict(aggs)
Serialize aggregation specs to the query to_dict shape: one
{"func": ..., "field": ..., "by": [...]} mapping per spec (fields spelled
as on the wire, by omitted when ungrouped), deterministically ordered.
Source code in ftmq/query/aggregations.py
make_agg(func, ref, groups=())
Validate and build a single Agg spec.
Groups are sorted (by wire spelling), so two specs over the same fields compare and serialize identically regardless of input order.
Source code in ftmq/query/aggregations.py
reduce_values(func, values)
Reduce collected values with an aggregation function (None if empty).
Source code in ftmq/query/aggregations.py
SQL
The SQL translation. A store passes its SqlSource to Query.compile (or builds Sql(query, source) directly).
Describes the SQL statement source a Query compiles
against: the SQLAlchemy table (or view), the entity-identity column, and an
optional partition-pruning rule.
Stores own one and pass it to Sql /
Query.compile. A downstream store with extra
columns (a lake / sharded table) supplies its own SqlSource so the same
Query compiles against it unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
table
|
Any
|
The SQLAlchemy |
required |
id_column
|
str
|
The entity-identity column name (default |
'canonical_id'
|
prune_schema
|
PruneFn | None
|
Optional function folding a schema/schemata filter into a
|
None
|
prune_column
|
str | None
|
The partition column the pruned values target
(e.g. |
None
|
base_filter
|
Any | None
|
Optional SQLAlchemy predicate folded into every compiled select and sub-select (e.g. a lake store's view filter). Unlike a predicate added post-hoc to the top-level select, this also scopes the entity-level membership / absence subqueries. |
None
|
Source code in ftmq/query/sql.py
Source code in ftmq/query/sql.py
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 | |
grouped_aggregations(grouper, limit=None)
Every aggregation spec grouped by grouper, as one select per spec
unioned to (field, func, group_value, value) rows.
The specs' rows join against the distinct (entity, group value) pairs
of the matching entities - distinct, so a multi-valued group property
does not multiply the aggregated rows within its buckets. One round
trip per grouper, instead of one per group value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grouper
|
Ref
|
The field reference to group by. |
required |
limit
|
int | None
|
Only the |
None
|
Source code in ftmq/query/sql.py
lookup(ref)
Where a field reference reads from in this source.
One registration per ref family, so nothing has to recover a field's
family from its name. A meta / context ref reads its own column and
needs no row predicate (every statement of an entity carries it); a
property or group ref reads the shared value column and selects its
rows via prop / prop_type.