TypeScript SDKDatasets

Execution

Validate, generate SQL, and execute dataset queries.

createDatasetClient is the execution surface for datasets. In a ClickHouse app, pass the same query builder instance you use for hand-written queries.

import { createDatasetClient } from '@hypequery/datasets';
import { createQueryBuilder } from '@hypequery/clickhouse';

const db = createQueryBuilder({
  url: process.env.CLICKHOUSE_URL!,
  username: process.env.CLICKHOUSE_USER!,
  password: process.env.CLICKHOUSE_PASSWORD!,
  database: process.env.CLICKHOUSE_DATABASE!,
});

const analytics = createDatasetClient({ queryBuilder: db });

Use db.table(...) for local typed queries and analytics.execute(...) for semantic dataset queries. Both paths share the same ClickHouse connection.

Execution methods

The dataset client exposes these methods:

MethodUse it for
analytics.validate(target, query, context?)Check a query without generating or executing SQL
analytics.toSQL(target, query, context?)Inspect generated SQL without executing it
analytics.compileDataset(dataset, query, context?)Preview execution SQL, effective limits, dependencies, and preflight statements
analytics.execute(target, query, context?)Validate, generate SQL, execute, and return rows

The target is a dataset. Handles from the older Metrics API are also accepted. compileDataset accepts datasets only and requires the query-builder execution path.

Validate

Use validate when you want errors as data instead of exceptions.

const validation = analytics.validate(Orders, {
  dimensions: ['country'],
  measures: ['revenue'],
  filters: [eq('status', 'completed')],
});

if (!validation.valid) {
  console.error(validation.errors);
}

Validation checks dimensions, measures, filters, order fields, limits, time grain requirements, tenant context, and derived measure plans.

Generate SQL

Use toSQL to inspect the generated query.

const sql = analytics.toSQL(Orders, {
  dimensions: ['country'],
  measures: ['revenue'],
  filters: [eq('status', 'completed')],
  orderBy: [{ field: 'revenue', direction: 'desc' }],
  limit: 10,
});

toSQL validates first. Invalid queries throw with the same validation errors that execute would throw.

Preview dataset execution

compileDataset and dataset execution use the same compilation pipeline for base, derived, window, and shift measures. Compilation does not execute a query. It includes the dataset's effective result ceiling and the extra row fetched to determine pagination.hasMore. Window and shift queries also expose their time-axis guard query in preflightStatements.

const query = { measures: ['revenue'], limit: 10 } as const;
const compiled = analytics.compileDataset(Orders, query);

// Structural diagnostics omit SQL, physical columns, filter values and tenant IDs.
console.log(compiled.describe());
// JSON.stringify(compiled) produces the same structural description.

const result = await analytics.execute(Orders, query);

Provide the same trusted tenant context and runtime builder override to compilation and execution. Invalid definitions or queries fail during compilation. SQL and parameters are available through compiled.sql and compiled.parameters for an authorized debugger; custom query builders may inline values into SQL, so those fields must not be returned as public diagnostics. The normalized compiled.query also contains filter values. toSQL retains its logical query behavior, including the requested limit; use compileDataset to preview the actual execution limit.

Execute a dataset

Dataset execution returns an ad hoc selection of dimensions and measures from one dataset.

const result = await analytics.execute(Orders, {
  dimensions: ['country', 'status'],
  measures: ['revenue', 'orderCount'],
  filters: [eq('status', 'completed')],
  limit: 10,
});

Dataset queries use the same by field when the dataset declares a timeKey:

const result = await analytics.execute(Orders, {
  by: 'day',
  dimensions: ['status'],
  measures: ['revenue', 'orderCount'],
});

Execution context

Pass execution context as the third argument. This is where runtime tenant scope and per-call builder overrides live.

await analytics.execute(Orders, {
  dimensions: ['country'],
  measures: ['revenue'],
}, {
  runtime: {
    tenant: 'tenant_123',
  },
});

When a dataset has tenantKey, tenant context is required unless you explicitly use a trusted cross-tenant scope. Datasets auto-inject the tenant filter from tenantKey.

Result metadata

execute returns rows plus metadata.

const result = await analytics.execute(Orders, {
  dimensions: ['country'],
  measures: ['revenue'],
  limit: 25,
});

result.data;
result.meta?.sql;
result.meta?.timingMs;
result.meta?.rowCount;
result.meta?.pagination;

Pagination metadata is present when a query sets limit. hypequery over-fetches one extra row to compute hasMore without issuing a separate count query.

{
  limit: 25,
  offset: 0,
  hasMore: true,
}

On this page

Get early access to hypequery cloud.

Cloud hosts the same model you run in your backend, with a managed API and MCP server, versions, and rollback. We're letting teams in a few at a time. Join the waitlist and we'll reach out when your project can go live.

How do you want to build your analytics layer? (Optional)
What features do you most need? (Optional)

Pick as many as you like.

Only your email is required. All other questions are optional.