Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions core-spec/expression_language.md
Original file line number Diff line number Diff line change
Expand Up @@ -709,11 +709,13 @@ The `dialect` field is a free-form string; the core specification does not enume

### Declaring Dialect-Specific Expressions

```
Put the portable expression in `sql` and keep vendor-specific variants in
`dialects`:

```yaml
expression:
sql: DATE_TRUNC('month', order_date)
dialects:
- dialect: ANSI_SQL
expression: DATE_TRUNC('month', order_date)
- dialect: SNOWFLAKE
expression: DATE_TRUNC('month', order_date)
- dialect: BIGQUERY
Expand Down
124 changes: 34 additions & 90 deletions core-spec/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,10 @@ datasets:
fields:
- name: order_id
expression:
dialects:
- dialect: ANSI_SQL
expression: order_id
sql: order_id
- name: order_number
expression:
dialects:
- dialect: ANSI_SQL
expression: order_number
sql: order_number
custom_extensions:
- vendor_name: DBT
data: '{"materialized": "table"}'
Expand Down Expand Up @@ -292,16 +288,14 @@ Within a dataset, field names and dataset-scoped metric names share one namespac

### Expression Object

The expression object supports multiple SQL dialects for cross-platform compatibility. Each field can define expressions in different dialects.
Use `sql` for the primary, portable expression. Optional vendor-specific variants
can be supplied in `dialects` (see the multi-dialect example below).

**Structure:**

```yaml
expression:
sql: "customer_id" # Primary, portable OSSIE_SQL_2026 form
dialects:
- dialect: ANSI_SQL # Free-form string; OSSIE_SQL_2026 is the only dialect the spec defines
expression: "customer_id" # Scalar SQL expression
```

**Key Points:**
Expand All @@ -327,9 +321,7 @@ expression:
```yaml
- name: customer_id
expression:
dialects:
- dialect: ANSI_SQL
expression: customer_id
sql: customer_id
description: Customer identifier
dimension:
is_time: false
Expand All @@ -340,9 +332,7 @@ expression:
```yaml
- name: full_name
expression:
dialects:
- dialect: ANSI_SQL
expression: first_name || ' ' || last_name
sql: first_name || ' ' || last_name
description: Customer full name
ai_context:
synonyms:
Expand All @@ -355,9 +345,7 @@ expression:
```yaml
- name: order_date
expression:
dialects:
- dialect: ANSI_SQL
expression: order_date
sql: order_date
datatype: Date
dimension:
is_time: true
Expand All @@ -373,9 +361,8 @@ expression:
```yaml
- name: email_normalized
expression:
sql: LOWER(email)
dialects:
- dialect: ANSI_SQL
expression: LOWER(email)
- dialect: SNOWFLAKE
expression: LOWER(email)::VARCHAR
- dialect: BIGQUERY
Expand Down Expand Up @@ -436,14 +423,15 @@ Metric expressions refer to dataset fields. They cannot refer to columns of a da

### Expression Object

The expression object supports multiple dialects
Use `sql` for the primary, portable metric expression. Optional vendor-specific

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block is now sql-only, but the text below it says vendor variants can be supplied in dialects, and the field section points to a "multi-dialect example below". No metric example shows that shape.
Someone writing a metric has nothing to copy.

Could we add a metric-level example with sql plus a vendor entry under dialects? That would also fit with keeping one dialects example in the examples files.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in commit 930aeaf. The metric expression documentation now includes a complete example combining portable SQL with a BigQuery-specific SAFE_DIVIDE dialect variant.

variants can be supplied in `dialects`.

```yaml
expression:
sql: "SUM(order.sales) / COUNT(DISTINCT order.customer_id)" # Primary, portable OSSIE_SQL_2026 form
dialects:
- dialect: ANSI_SQL # Default
expression: "SUM(order.sales) / COUNT(DISTINCT order.customer_id)"
- dialect: BIGQUERY
expression: "SAFE_DIVIDE(SUM(order.sales), COUNT(DISTINCT order.customer_id))"
```

At least one of the top-level `sql` or `dialects` MUST be present; either MAY stand alone. When both a top-level `sql` and an `OSSIE_SQL_2026` entry in `dialects` are present, the top-level `sql` is authoritative.
Expand All @@ -455,9 +443,7 @@ At least one of the top-level `sql` or `dialects` MUST be present; either MAY st
```yaml
- name: total_revenue
expression:
dialects:
- dialect: ANSI_SQL
expression: SUM(orders.amount)
sql: SUM(orders.amount)
description: Total revenue across all orders
datatype: Decimal
ai_context:
Expand All @@ -471,9 +457,7 @@ At least one of the top-level `sql` or `dialects` MUST be present; either MAY st
```yaml
- name: avg_orders
expression:
dialects:
- dialect: ANSI_SQL
expression: SUM(orders.amount) / COUNT(DISTINCT customers.id)
sql: SUM(orders.amount) / COUNT(DISTINCT customers.id)
description: Average orders
datatype: Decimal
ai_context:
Expand Down Expand Up @@ -512,31 +496,23 @@ datasets:
fields:
- name: order_id
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: order_id
sql: order_id
description: Order identifier
- name: net_amount
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: amount - discount
sql: amount - discount
description: Order amount after discount

metrics:
- name: total_net_amount
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: SUM(net_amount)
sql: SUM(net_amount)
description: Total order amount after discount
datatype: Decimal

- name: order_count
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: COUNT(order_id)
sql: COUNT(order_id)
description: Number of orders
datatype: Integer
```
Expand All @@ -552,17 +528,13 @@ datasets:
fields:
- name: net_amount
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: amount - discount
sql: amount - discount
metrics:
# INVALID (rule 1): references the customers dataset, so this metric is
# model-scoped and belongs in the model-root metrics
- name: revenue_per_customer
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: SUM(net_amount) / COUNT(DISTINCT customers.id)
sql: SUM(net_amount) / COUNT(DISTINCT customers.id)
```

---
Expand Down Expand Up @@ -636,24 +608,16 @@ datasets:
fields:
- name: order_id
expression:
dialects:
- dialect: ANSI_SQL
expression: o_orderkey # source column
sql: o_orderkey # source column
- name: customer_id
expression:
dialects:
- dialect: ANSI_SQL
expression: o_custkey
sql: o_custkey
- name: total_amount
expression:
dialects:
- dialect: ANSI_SQL
expression: o_totalprice
sql: o_totalprice
- name: total_usd
expression:
dialects:
- dialect: ANSI_SQL
expression: total_cents / 100.0
sql: total_cents / 100.0

relationships:
- name: orders_to_customers
Expand All @@ -665,9 +629,7 @@ relationships:
metrics:
- name: total_revenue
expression:
dialects:
- dialect: ANSI_SQL
expression: SUM(orders.total_usd) # field, not a source column
sql: SUM(orders.total_usd) # field, not a source column
```

In this model, these references are invalid:
Expand Down Expand Up @@ -719,42 +681,32 @@ datasets:
fields:
- name: order_id
expression:
dialects:
- dialect: ANSI_SQL
expression: order_id
sql: order_id
description: Order identifier

- name: customer_id
expression:
dialects:
- dialect: ANSI_SQL
expression: customer_id
sql: customer_id
description: Customer identifier

- name: order_date
expression:
dialects:
- dialect: ANSI_SQL
expression: order_date
sql: order_date
datatype: Date
dimension:
is_time: true
description: Order date

- name: amount
expression:
dialects:
- dialect: ANSI_SQL
expression: amount
sql: amount
description: Order amount

# Dataset-scoped: resolves entirely within the orders dataset
metrics:
- name: total_amount
expression:
dialects:
- dialect: ANSI_SQL
expression: SUM(amount)
sql: SUM(amount)
description: Total order amount
datatype: Decimal

Expand All @@ -765,25 +717,19 @@ datasets:
fields:
- name: id
expression:
dialects:
- dialect: ANSI_SQL
expression: id
sql: id
description: Customer identifier

- name: email
expression:
dialects:
- dialect: ANSI_SQL
expression: email
sql: email
description: Customer email

# Dataset-scoped: resolves entirely within the customers dataset
metrics:
- name: customer_count
expression:
dialects:
- dialect: ANSI_SQL
expression: COUNT(DISTINCT id)
sql: COUNT(DISTINCT id)
description: Total number of customers
datatype: Integer
ai_context:
Expand All @@ -802,9 +748,7 @@ metrics:
# Model-scoped: spans orders and customers via the relationship
- name: revenue_per_customer
expression:
dialects:
- dialect: ANSI_SQL
expression: SUM(orders.amount) / COUNT(DISTINCT customers.id)
sql: SUM(orders.amount) / COUNT(DISTINCT customers.id)
description: Average revenue per customer
datatype: Decimal

Expand Down
Loading
Loading