Dimensions
Define typed fields for selecting, grouping, and filtering dataset queries.
Dimensions are the non-aggregated fields in a dataset. They are the fields callers can select, group by, filter on, and order by.
The object key is the semantic API name. The dimension helper tells hypequery the field type, and the options tell hypequery how that semantic field maps to ClickHouse.
dimensions: {
id: dimension.string(),
status: dimension.string({ label: 'Status' }),
isTrial: dimension.boolean({ column: 'is_trial' }),
createdAt: dimension.timestamp({ column: 'created_at' }),
}With that definition, callers use the semantic names:
await analytics.execute(Orders, {
dimensions: ['status', 'createdAt'],
measures: ['revenue'],
});The generated SQL still uses the mapped ClickHouse columns, such as created_at.
Dimension helpers
dimension.string(opts?)dimension.number(opts?)dimension.boolean(opts?)dimension.timestamp(opts?)
The helper should match the value type of the field. That type is used for query validation, generated contracts, and integration surfaces.
These are semantic dimension types, not a full mirror of every ClickHouse physical type. Use the closest analytical type:
| ClickHouse types | Dimension type |
|---|---|
String, LowCardinality(String), Enum, UUID | dimension.string() |
UInt64, Int32, Float64, Decimal | dimension.number() |
Bool or boolean-style UInt8 flags | dimension.boolean() |
Date, DateTime, DateTime64 | dimension.timestamp() |
The query builder can still use precise generated ClickHouse schema types. Datasets expose a smaller semantic model for analytics, validation, docs, and integrations.
Options
Every dimension helper accepts the same options object:
type DimensionOptions = {
label?: string;
description?: string;
column?: string;
sql?: string;
filterable?: boolean;
groupable?: boolean;
};| Option | Use it for |
|---|---|
column | Mapping a semantic field name to a physical ClickHouse column |
sql | Backing a dimension with a SQL expression instead of a simple column |
label | Human-readable display text for docs, UIs, and agents |
description | Longer metadata for generated docs, UIs, and agents |
filterable | Whether callers should be allowed to filter on the dimension. Defaults to true |
groupable | Whether callers should be allowed to group/select the dimension. Defaults to true in the semantic model |
Column mapping
Use opts.column when the semantic field name differs from the physical column name.
dimensions: {
userId: dimension.string({ column: 'user_id' }),
isActive: dimension.boolean({ column: 'is_active' }),
createdAt: dimension.timestamp({ column: 'created_at' }),
}This keeps your public dataset API idiomatic while still targeting the real table columns:
await analytics.execute(Users, {
dimensions: ['userId', 'createdAt'],
});Labels and descriptions
Use label and description for human-readable metadata. These do not change SQL generation, but they are exposed through generated docs and MCP schema introspection so agents and UIs can understand what a field means.
dimensions: {
status: dimension.string({
label: 'Order Status',
description: 'Current lifecycle state for the order.',
}),
}For MCP, this metadata becomes part of get_dataset_schema, which helps agents choose the right fields without guessing from column names alone.
SQL-backed dimensions
Use sql when the dimension is computed rather than stored as a single column.
dimensions: {
countryCode: dimension.string({ column: 'country_code' }),
countryUpper: dimension.string({ sql: 'upper(country_code)' }),
}Use SQL-backed dimensions sparingly. Schema compatibility checks can inspect simple column references, but complex SQL expressions can only produce warnings because they cannot be fully verified from the table schema.
Filterable and groupable
Use filterable and groupable when a field exists in the dataset contract but should not be available for every query operation.
dimensions: {
email: dimension.string({
filterable: true,
groupable: false,
description: 'Allowed in filters, but not useful as a grouping key.',
}),
}Most dimensions can omit these options. By default, dimensions are available for filtering and grouping. Set filterable: false to remove a dimension from the automatically generated filter set.
groupable records the intended grouping behavior on the dimension definition. Use it to communicate stricter query intent to generated docs, UIs, or integration layers.