Relationships
Link Python datasets and query to-one related fields one hop deep.
Relationships model how one dataset links to another. To-one relationships (belongs_to, has_one) are
queryable: dataset queries can select, filter, and order by fields on the related dataset one hop deep, and
hypequery executes the join for you. To-many relationships (has_many) are metadata only.
Defining relationships
Pass the target dataset (or a function returning it). from_field is the join column on this dataset's table and
to_field is the join column on the target's table.
from hypequery.datasets import (
Dataset,
belongs_to,
create_dataset_client,
create_dataset_registry,
dimension,
has_many,
measure,
)
customers = Dataset(
name="customers",
source="customers",
dimensions={
"id": dimension("string"),
"country": dimension("string"),
"tier": dimension("string"),
},
)
line_items = Dataset(
name="line_items",
source="line_items",
dimensions={"id": dimension("string"), "sku": dimension("string")},
)
orders = Dataset(
name="orders",
source="orders",
dimensions={
"id": dimension("string"),
"status": dimension("string"),
"amount": dimension("number"),
},
measures={"revenue": measure.sum("amount")},
relationships={
"customer": belongs_to(customers, from_field="customer_id", to_field="id"),
"items": has_many(line_items, from_field="id", to_field="order_id"),
},
)
# The registry resolves relationship targets at query time.
analytics = create_dataset_client(
executor=executor,
registry=create_dataset_registry(orders, customers, line_items),
)belongs_to: many-to-one; the foreign key is on this table (orders.customer_id → customers.id).has_one: one-to-one; the foreign key is on the target table.has_many: one-to-many; the foreign key is on the target table. Metadata only.
Querying related fields
Reference to-one related dimensions as <relationship>.<dimension> in dimensions, filters, and ordering:
from hypequery.datasets import DatasetQuery, filter, order
result = analytics.execute(
"orders",
DatasetQuery(
dimensions=("customer.country",),
measures=("revenue",),
filters=(filter.eq("customer.tier", "enterprise"),),
order_by=(order.asc("customer.country"),),
),
)A target can be a Dataset or the name of a registered dataset.
Served endpoints don't expose related fields unless you opt in per relationship with
include_related. See Dataset endpoints.
Checking join keys
check_relationships(dataset, *, executor, registry, context=None, relationships=None) runs scoped uniqueness checks
on the physical target keys of each to-one relationship and reports duplicates, so a belongs_to that would fan out
rows is caught before it reaches a dashboard. check_relationships_async is the async form. Both respect the tenant
scope, deadline, and cancellation in context, and neither runs unless you call it.