angee.graphql.data.metadata
GraphQL projection and attachment of neutral data-surface descriptions.
DATA_RESOURCE_METADATA_ATTR
Attribute attached to schema surfaces that contribute model resource metadata.
data_resource_metadata
def data_resource_metadata(
surface: object) -> tuple[data_contract.DataResourceMetadata, ...]Return model resource metadata attached to surface.
readable_model_field_names
def readable_model_field_names(
metadata: data_contract.DataResourceMetadata) -> frozenset[str]Return concrete model fields projected readably by the GraphQL node.
make_data_resource_metadata
def make_data_resource_metadata(
*,
model: type[models.Model] | None = None,
roots: data_contract.DataResourceRoots,
type_names: data_contract.DataResourceTypeNames,
capabilities: tuple[str, ...],
node_type: type | None = None,
filter_type: type | None = None,
order_type: type | None = None,
filter_fields: tuple[str, ...] = (),
order_fields: tuple[str, ...] = (),
aggregate_fields: tuple[str, ...] = (),
group_by_fields: tuple[str, ...] = (),
group_dimensions: tuple[data_contract.DataGroupDimensionMetadata,
...] = (),
aggregate_measures: tuple[data_contract.DataAggregateMeasureMetadata,
...] = (),
default_measures: tuple[data_contract.DataAggregateMeasureMetadata,
...] = (),
default_sort: tuple[data_contract.DataDefaultSortMetadata, ...] = (),
create_input_type: type | None = None,
update_input_type: type | None = None,
create_fields: tuple[str, ...] = (),
update_fields: tuple[str, ...] = (),
required_create_fields: tuple[str, ...] = (),
revision_fields: tuple[str, ...] = (),
relation_axes: tuple[data_contract.DataRelationAxisMetadata, ...] = (),
group_aliases: tuple[data_contract.DataGroupAliasMetadata, ...] = (),
lines: data_contract.DataLinesMetadata | None = None,
fields: tuple[data_contract.DataResourceFieldMetadata, ...] = (),
subtitle: data_contract.DataResourceSubtitleMetadata | None = None,
model_label: str | None = None,
public_id_field: str = PUBLIC_ID_FIELD_NAME,
row_model: str = "server") -> data_contract.DataResourceMetadataBuild one resource metadata contribution from an owning schema surface.
model is the owning Django model for a model-backed resource. A computed (non-model) resource passes model=None and a dotted model_label (e.g. "platform.addon"); the model is only ever used internally (it is {"wire": False}), so the wire payload is identical either way.
row_model is the client/server boundary signal the frontend reads ("server" by default — Hasura where/order_by/limit + the _groups aggregate; "client" for a small computed set that fetches once and filters/sorts/paginates/groups in the browser).
attach_data_resource_metadata
def attach_data_resource_metadata(
surface: type[_SurfaceT],
metadata: data_contract.DataResourceMetadata) -> type[_SurfaceT]Attach model resource metadata to a generated Strawberry surface.
Only query/mutation/subscription roots are scanned for resource metadata, so an addon that extends another model's GraphQL type (a type_extensions entry adds fields to the node, never to the model's resource projection) anchors its contribution on one of its own root surfaces — typically its action-mutation bucket — and the per-model merge (:func:angee.data.metadata.merge_data_resources) folds it into the owning model's resource by model label. Fields only a server verb advances are contributed read-only (neither creatable nor updatable).
relation_group_by_fields
def relation_group_by_fields(
node_type: type, model: type[models.Model],
group_by_fields: tuple[str, ...]) -> tuple[str, ...]Add one ORM-backed display axis for each direct relation group axis.
The Hasura group-key type is built before resource metadata is attached, so relation labels must enter the group declaration at this seam. Explicit scalar relation-leaf axes keep ownership. Otherwise the related Strawberry object supplies the record-representation precedence, while Django confirms the selected label is a concrete string column that aggregation may group by. Computed labels therefore fall through to the next model-backed display field (for example, UserType.display_name falls back to username).