AML Quick Reference
Quick syntax lookup for commonly used AML patterns
Introduction
This page provides condensed code examples for quick reference when writing AML. For detailed explanations and parameter definitions, see the full reference pages linked in the table below.
| AML Dataset | Jump to example | Full Reference |
| AML Model | Jump to example | Full Reference |
| AML Fields | Jump to example | Full Reference |
| AML Relationship | Jump to example | Full Reference |
| AML Dataset Fields | Jump to example | Full Reference |
| AML Constant | Jump to example | Full Reference |
| AML Function | Jump to example | Full Reference |
| AML Module | Jump to example | Full Reference |
| AML Extend | Jump to example | Full Reference |
| AML Partial | Jump to example | Full Reference |
| AML If-else | Jump to example | Full Reference |
| AML String Interpolation | Jump to example | Full Reference |
Dataset File
Dataset raw_ecommerce {
label: 'Raw Ecommerce'
description: "This Dataset is about Ecommerce data"
owner: '[email protected]'
data_source_name: 'demodb'
models: [
users,
orders
]
relationships: [
// define relationship between orders and users is many to one
relationship(orders.user_id > users.id, true)
]
}Model File
Table Model
Model users {
type: 'table'
label: "Users"
data_source_name: 'bigquery_dw'
table_name: 'users'
dimension id {
label: 'ID'
type: 'number'
hidden: false // optional
definition: @sql {{#SOURCE.id}};; // optional
}
dimension email {
label: 'Email'
type: 'number'
// without "definition", it automatically uses the same column name as the dimension name ('email')
}
measure user_count {
type: 'number'
label: 'Count Users'
definition: @aql count(users.id) ;;
}
}Query Model
Model location {
type: 'query'
label: 'Location'
data_source_name: 'demodb'
models: [cities, countries]
query: @sql
select {{ #ci.id }} as city_id
, {{ #ci.name }} as city_name
, {{ #co.code }} as country_code
, {{ #co.name }} as country_name
, {{ #co.continent_name }}
from {{ #cities as ci }}
left join {{ #countries as co }} on {{ #co.code }} = {{ #ci.country_code }};;
dimension city_id {
label: 'City Id'
type: 'number'
}
dimension city_name {
label: 'City Name'
type: 'text'
}
dimension country_code {
label: 'Country Code'
type: 'text'
}
dimension country_name {
label: 'Country Name'
type: 'text'
}
dimension continent_name {
label: 'Continent Name'
type: 'text'
}
}Measure
measure total_orders {
label: 'Total Orders'
type: 'number'
definition: @aql count(orders.id) ;;
}
measure total_users {
label: 'Total Users'
type: 'number'
definition: @aql count(users.id) ;;
}Dimension
// This is a simple dimension. The compiler assumes there is a `created_at` column in your
// underlying table
dimension created_at {
label: 'Created At'
type: 'datetime'
}
// This is a derived dimension based on the dimension above, using AQL.
dimension created_at_year {
label: 'Created At Year'
type: 'number'
definition: @aql date_part('year', orders.created_at) ;;
}
// This is a simple dimension, with explicitly defined column name.
dimension status {
label: 'Status'
type: 'text'
// If you don't include this line, the compiler uses the table's column that bears the
// same name as the dimension (i.e. status).
definition: @sql {{ #SOURCE.status }};;
}
// This is a dimension which uses AQL case-when syntax.
dimension age_group {
label: 'User Age Group'
description: "'Under 18', '18 - 22', '23 - 30', '31 - 40', 'Over 40'"
type: 'text'
hidden: false
definition: @aql case(
when: users.age < 18, then: 'Under 18',
when: users.age >= 18 and users.age < 23, then: '18 - 22',
when: users.age >= 23 and users.age < 31, then: '23 - 30',
when: users.age >= 31 and users.age < 41, then: '31 - 40',
else: 'Over 40'
) ;;
}
// This is a dimension to extract month's name from the base dimension `created_at`.
dimension month_name {
label: 'Month Name'
type: 'text'
definition: @aql date_format(orders.created_at, '%m - %B') ;; // example output: '12 - December'
}Relationship File
Full-form Relationship
// Relationship full form defined in dataset file
RelationshipConfig {
rel: Relationship {
type: 'many_to_one'
from: r(products.merchant_id)
to: r(merchants.id)
}
active: true
},
// Relationship defined in model file
Relationship relationship_name {
type: 'many_to_one'
from: r(orders.user_id)
to: r(users.id)
}
Short-form Relationship
Many-to-One relationship
// Relationship short form defined in dataset file, relationship type > is many_to_one
relationship(ecommerce_cities.country_code > ecommerce_countries.code, true, 'one_way')One-to-One relationship
// Relationship short form defined in dataset file, relationship type - is one_to_one
relationship(ecommerce_merchants.admin_id - ecommerce_users.id, true)Dataset Fields
Dataset-level dimensions and metrics support cross-model calculations that span multiple models.
Dataset Dimension
Dataset e_commerce {
// ...
dimension full_name {
model: users
type: 'text'
label: 'Full Name'
definition: @aql concat(users.first_name, ' ', users.last_name);;
}
}Dataset Metric
Dataset ecommerce {
// ...
// Simple aggregation
metric count_orders {
label: 'Count Orders'
type: 'number'
definition: @aql count(orders.id) ;;
}
// Cross-model aggregation
metric sum_order_value {
label: 'Sum Order Values'
type: 'number'
definition: @aql sum(order_items, order_items.quantity * products.price) ;;
}
}Constant
const signup_threshold = 0.6
const greeting = 'Hello'
// Explicit type
Number tax_rate = 0.08
// Used in a dataset metric via string interpolation
Dataset my_dataset {
metric active_users {
definition: @aql count(*)
| where users.signup_rate > ${signup_threshold}
;;
}
}Function
// Simple function
Func double(x: Number) {
x * 2
}
// Function that returns a VizBlock
Func revenue_chart(dataset: String) {
VizBlock {
label: 'Revenue'
viz: BarChart {
dataset: dataset
series {
field { ref: r(orders.revenue), aggregation: 'sum' }
}
}
}
}
// Call the function
revenue_chart('ecommerce')Module
Modules are directories under modules/ in your AML project root.
|-- datasets/
| |-- ecommerce.dataset.aml
|-- modules/
| |-- cohort/
| | |-- retention.aml
| |-- utils/
| |-- date_helpers.amlReference objects from a submodule using dot notation:
// datasets/ecommerce.dataset.aml
Dataset ecommerce {
models: [
orders,
cohort.retention_table // model from the cohort submodule
]
}Import specific objects into the current file's scope with use:
use cohort { retention_table }
use utils { date_helpers: dates } // alias date_helpers to datesExtend
Extend an existing object to create a new one, adding or overriding properties.
Model users {
dimension id { type: 'number' }
dimension email { type: 'text' }
dimension salary { type: 'number', hidden: false }
}
// Add a new dimension
Model users_with_activation = users.extend({
dimension activated_at { type: 'datetime' }
})
// Override a property without re-declaring everything
Model users_anonymized = users.extend({
dimension salary { hidden: true }
})Partial
A partial extracts reusable properties that can be applied to multiple objects via .extend().
PartialModel timestamp_fields {
dimension created_at {
type: 'datetime'
definition: @sql {{ #SOURCE.created_at }};;
}
dimension updated_at {
type: 'datetime'
definition: @sql {{ #SOURCE.updated_at }};;
}
}Model users_base {
type: 'table'
table_name: 'public.users'
data_source_name: 'demodb'
dimension id { type: 'number' }
}
Model users = users_base.extend(timestamp_fields)Partials also work at the Dataset level:
PartialDataset revenue_metrics {
metric gmv { definition: @aql sum(orders.gmv);; }
metric mrr { definition: @aql sum(subscriptions.mrr);; }
}
Dataset company = company_base.extend(revenue_metrics)
Dataset store = store_base.extend(revenue_metrics)If-else
const score = 85
const grade = if (score >= 90) {
'A'
} else if (score >= 75) {
'B'
} else {
'C'
}
// grade is 'B'Commonly used inside functions to switch logic based on a parameter:
Func kpi_block(metric: 'revenue' | 'orders') {
const measure_ref = if (metric == 'revenue') {
r(orders.revenue)
} else {
r(orders.id)
}
VizBlock {
label: "KPI -- ${metric}"
viz: SingleValue {
dataset: 'ecommerce'
series {
field {
ref: measure_ref
aggregation: if (metric == 'revenue') { 'sum' } else { 'count' }
}
}
}
}
}String Interpolation
Embed variable values directly into strings using ${}.
const env = 'production'
const schema = 'analytics'
// In a string
const table_path = '${schema}.orders' // 'analytics.orders'
// In a heredoc (SQL definition)
@sql select * from ${schema}.orders ;;
// In a function label
Func chart(title: String) {
VizBlock {
label: 'Chart -- ${title}'
}
}
// Combined with if-else
Func greet(name: 'John' | 'Alice') {
"Hello, ${if (name == 'John') { 'sir' } else { 'madam' }}!"
}