Our engine never sees your warehouse password
datahashi

Semantic model

Entities, dimensions, measures, metrics, grains, and join graphs in a datahashi model.

Updated

This page defines the terms in a datahashi model. The same terms appear in the YAML spec, the REST API, the MCP tools, and the console.

flowchart LR
    subgraph O["Entity: Order"]
        direction TB
        O1["Dimensions: id (PK), order_date (day), status<br/>Measures: revenue, order_count"]
    end
    subgraph Cu["Entity: Customer"]
        direction TB
        C1["Dimensions: id (PK), region, plan_tier<br/>Measures: customer_count"]
    end
    O -->|"many-to-one join<br/>(Join Graph)"| Cu
    O --> M["Top-level metrics<br/>avg_order_value = revenue / order_count<br/>revenue_growth_yoy = (revenue − offset(revenue, 1 year)) / offset(revenue, 1 year)"]

Modeling primitives

Semantic Model

The versioned set of definitions that maps warehouse tables to business names. The YAML file has no name key. A published model has a version. Pin that version with version on a query. The model header source names the Connection.

Entity

A business noun with a primary key and relationships to other entities. Examples: Customer, Order.

  • Physical mapping. A warehouse table (table: public.orders) or custom SQL (sql: "SELECT ... FROM ...").
  • Inheritance. An entity can extend another entity with extends: BaseEntity. It inherits fields.
  • Join sugar. An entity can declare joins: to related entities.

Dimension

An attribute of an entity. You group, filter, or slice on it. Examples: region, status, ordered_at.

  • Standard dimension. A warehouse column.
  • Calculated dimension. An opaque SQL expression (expr: "CASE WHEN amount > 100 THEN 'large' ELSE 'small' END").
  • Time dimension. Declares time buckets called grains (for example [day, month, quarter, year]).
  • Fiscal calendar. Set fiscal_year_start_month (1–12) to use fiscal_quarter and fiscal_year.

Grain

A time bucket on a time dimension in a query.

  • Standard grains: minute, hour, day, week (ISO-Monday), month, quarter, year.
  • Fiscal grains: fiscal_quarter, fiscal_year. These need fiscal_year_start_month on the dimension.
  • Each selected time dimension takes at most one grain per query.

Measure vs Metric

The compiler treats Measure and Metric as different kinds:

Concept Definition Example Who may select it?
Measure Raw aggregatable field on an entity. Evaluated in the first aggregation. sum(amount), count(id), min(price) Only a grant that exposes that measure
Metric Named formula over measures. Computed after aggregation. revenue / order_count A grant on the metric, when every entity it reads is also granted

Measure aggregations

  • Additive: sum, count, min, max.
  • Non-additive / approx: count_distinct, count_distinct_approx.
  • Percentiles: median, p90, p95, p99 (PostgreSQL, Snowflake, BigQuery, DuckDB).
  • Filtered measures: Conditions inside the aggregate (filters: [{ dimension: status, op: eq, value: completed }]).
  • Rolling windows: Trailing or cumulative time windows (rolling_window: { trailing: 30 day }).

Metric expressions

  • Arithmetic. A formula over measures and constants (expr: revenue / order_count).
  • Derived metrics. A metric can name another metric (expr: profit / revenue). The engine inlines the reference at publish. It rejects cycles.
  • Period-over-period. offset(expr, interval) (for example offset(revenue, 1 year)). After inlining, expr must be one bare measure.
  • Multi-stage metrics. Two-pass aggregations such as avg_per(revenue, customer_id) or max_per(revenue, store_id). The engine computes a value per entity first. Then it computes the outer metric.

Join Graph

The directed graph of entities. Named relationships carry cardinality (many_to_one, one_to_many, one_to_one). There is no many_to_many. Model a bridge entity.

The compiler resolves join paths. Relationship names are unique in the model. Role-playing joins such as bill_to_customer and ship_to_customer stay distinct.

Segment

A named filter on the model (segments:). A query can reference it by name. Segments expand into concrete filters before row-level security runs.

View

A curated projection of a semantic model. It exposes a subset of metrics and dimensions. It can add predefined filters. A view can only narrow access. It cannot widen access. It cannot bypass data roles.

Query and access

Semantic Query

The structured request over REST or MCP. It contains:

  • version: Optional published model version. There is no model field.
  • metrics: Governed metric names.
  • measures: Raw measure names. Refused when the caller’s grants omit them.
  • dimensions: Group-by dimensions with optional grain.
  • filters: Flat { dimension, op, value } conditions, combined with AND.
  • filter_group: Nested {op, filters, groups} boolean logic.
  • having: { ref, op, value } conditions after aggregation.
  • order: { ref, desc } sort specifications.
  • limit and offset: Pagination. offset needs a positive limit and an order.

Governed mode vs Explore mode

  • Grants without raw measures. The usual surface for API consumers, agents, and apps. Named metrics and curated views only. A raw measure is refused.
  • Grants that include measures. Metrics and raw measures across the Join Graph. This is not a separate request mode.

Data Role

A named set of grants in the policy bundle. A role grants entities, fields, and metrics. It can attach a row filter (row_filter: "region = current_user.region"). A principal with several data roles gets a union of grants and an intersection of row filters.

Resilience and metadata

Drift resilience

  • Rename alias (renamed_from). Previous names for a dimension, measure, or metric. The compiler maps the old name to the new name.
  • Deprecation (deprecated: true). The field stays queryable. Catalog discovery shows a warning.

Documentation metadata

  • tags:. String labels shown on catalog entries. They are not a filter on POST /v1/catalog.
  • owner:. Team or person who maintains the definition.
  • meta:. Key-value bag for downstream tools.

Next: Query Runner · Rollups · Data roles and row-level security.