> hypequery

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 typesDimension type
String, LowCardinality(String), Enum, UUIDdimension.string()
UInt64, Int32, Float64, Decimaldimension.number()
Bool or boolean-style UInt8 flagsdimension.boolean()
Date, DateTime, DateTime64dimension.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;
};
OptionUse it for
columnMapping a semantic field name to a physical ClickHouse column
sqlBacking a dimension with a SQL expression instead of a simple column
labelHuman-readable display text for docs, UIs, and agents
descriptionLonger metadata for generated docs, UIs, and agents
filterableWhether callers should be allowed to filter on the dimension. Defaults to true
groupableWhether 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.

On this page