We value your privacy

This site uses cookies to improve your browsing experience, analyze site traffic, and show personalized content. See our Privacy Policy.

  1. MooseStack
  2. Query Layer

Query Layer API

MooseTip:

The Query Layer is currently available for TypeScript only.

The Query Layer provides a type-safe abstraction for building SQL queries against ClickHouse. Define semantic query models with dimensions, metrics, filters, and sorting — and the Query Layer generates optimized SQL automatically.

import { defineQueryModel, buildQuery, count, sum, timeDimensions } from "@514labs/moose-lib";

defineQueryModel

Creates a reusable, type-safe query model that maps semantic concepts to ClickHouse SQL.

const visitsModel = defineQueryModel({  name: "query_visits",  description: "Analyze visit data by status and time",  table: VisitsTable,   dimensions: {    status: { column: "status" },    ...timeDimensions(VisitsTable.columns.timestamp),  },   metrics: {    totalVisits: { agg: count(), as: "total_visits" },    totalRevenue: { agg: sum(VisitsTable.columns.amount), as: "total_revenue" },  },   filters: {    status: { column: "status", operators: ["eq", "in"] as const },    amount: { column: "amount", operators: ["gte", "lte"] as const },    totalRevenue: { metric: "totalRevenue", operators: ["gte"] as const },  },   columns: {    visitId: { column: "id" },    userName: { join: "user", column: "first_name" },  },   joins: {    user: {      table: UsersTable,      leftKey: "user_id",      rightKey: "id",      type: "LEFT",    },  },   sortable: ["day", "totalVisits", "totalRevenue"] as const,   defaults: { limit: 100, maxLimit: 1000, orderBy: [["day", "DESC"]] },});

QueryModelConfig

PropertyTypeRequiredDescription
namestringNoTool name for MCP registration
descriptionstringNoTool description for MCP
tableOlapTable<T>YesThe ClickHouse table to query
dimensionsRecord<string, DimensionDef>NoGrouping fields (GROUP BY)
metricsRecord<string, MetricDef>NoAggregate functions
columnsRecord<string, ColumnDef>NoDetail mode fields (non-aggregated)
joinsRecord<string, JoinDef>NoJOIN definitions
filtersRecord<string, ModelFilterDef>YesFilterable fields with allowed operators
sortablereadonly string[]YesFields that can be sorted
defaultsobjectNoDefault limit, maxLimit, orderBy, dimensions, metrics, columns

DimensionDef

PropertyTypeDescription
columnkeyof TModelColumn name for simple fields
expressionSqlCustom SQL expression (alternative to column)
asstringOutput alias

MetricDef

PropertyTypeDescription
aggSqlAggregation expression (e.g., count(), sum(col))
asstringOutput column alias

ColumnDef

PropertyTypeDescription
columnkeyof TModel | stringColumn name
joinstringJoin key (references a key in joins)
asstringOutput alias

JoinDef

PropertyTypeDescription
tableOlapTable<any>The table to join
onSqlCustom ON clause (alternative to leftKey/rightKey)
leftKeystringLeft table column name
rightKeystringRight table column name
type"LEFT" | "INNER"Join type (default: "LEFT")

ModelFilterDef

PropertyTypeDescription
columnkeyof TModelTable column to filter (WHERE)
metricstringMetric name to filter (HAVING) — mutually exclusive with column
operatorsreadonly FilterOperator[]Allowed operators
transform(value) => SqlValueOptional value transformer
inputTypeFilterInputTypeHintUI hint: "text", "number", "date", "select", "multiselect"
requiredtrueMake the eq parameter required for MCP

Filter Operators

OperatorValue TypeSQL Output
"eq"Tcol = value
"ne"Tcol != value
"gt", "gte", "lt", "lte"Tcol > value, col >= value, etc.
"like", "ilike"stringcol LIKE pattern, col ILIKE pattern
"in", "notIn"T[]col IN (...), col NOT IN (...)
"between"[T, T]col BETWEEN low AND high
"isNull", "isNotNull"booleancol IS NULL, col IS NOT NULL

QueryModel

The object returned by defineQueryModel().

Properties

PropertyTypeDescription
namestring | undefinedModel name
descriptionstring | undefinedModel description
defaultsobjectDefault query behavior
filtersTFiltersFilter definitions
sortablereadonly TSortable[]Sortable field names
dimensionNamesreadonly string[]Dimension key names
metricNamesreadonly string[]Metric key names
columnNamesreadonly string[]Column key names

Type Inference Helpers

type DimNames = typeof model.$inferDimensions;   // "status" | "day" | ...type MetNames = typeof model.$inferMetrics;       // "totalVisits" | "totalRevenue" | ...type ColNames = typeof model.$inferColumns;       // "visitId" | "userName" | ...type Filters  = typeof model.$inferFilters;       // Full FilterParams typetype Request  = typeof model.$inferRequest;       // Full QueryRequest typetype Result   = typeof model.$inferResult;        // Expected row type

Methods

query(request, client) — Execute a query and return typed results.

const results = await model.query(  {    dimensions: ["status", "day"],    metrics: ["totalVisits"],    filters: { status: { eq: "active" } },    orderBy: [["day", "DESC"]],    limit: 10,  },  queryClient,);

toSql(request) — Generate SQL without executing.

toParts(request) — Get individual SQL clause parts (select, from, where, groupBy, having, orderBy, pagination, conditions[]) for custom assembly.

const parts = model.toParts(request);const customSql = sql`  ${parts.select}  ${parts.from}  WHERE ${parts.conditions[0]} OR ${parts.conditions[1]}  ${parts.groupBy}  ${parts.orderBy}  LIMIT 50`;

QueryRequest

PropertyTypeDescription
filtersFilterParams<TFilters>Nested filter conditions
dimensionsTDimensions[]Dimension fields to group by
metricsTMetrics[]Aggregate metrics to compute
columnsTColumns[]Detail mode columns (no GROUP BY)
orderByArray<[TSortable, SortDir]>Multi-column sort
limitnumberMaximum rows to return
pagenumber0-indexed page number
offsetnumberExplicit offset (mutually exclusive with page)

buildQuery

Fluent, chainable API for constructing queries against a model.

import { buildQuery } from "@514labs/moose-lib"; const results = await buildQuery(visitsModel)  .dimensions(["day", "status"])  .metrics(["totalVisits", "totalRevenue"])  .filter("status", "eq", "active")  .filter("amount", "gte", 50)  .orderBy(["totalRevenue", "DESC"])  .limit(50)  .execute(queryClient);

Chainable Methods

MethodDescription
.dimensions(fields)Set dimension fields to group by
.metrics(fields)Set aggregate metrics to compute
.columns(fields)Set detail mode columns (no GROUP BY)
.filter(name, op, value)Add a filter condition (skipped if value is undefined)
.orderBy(...[field, dir])Set sort order
.limit(n)Set maximum rows
.page(n)Set page number (0-indexed)
.offset(n)Set explicit offset

Terminal Methods

MethodDescription
.build()Return the QueryRequest object
.toSql()Generate SQL without executing
.toParts()Get individual SQL clause parts
.assemble(fn)Get parts and apply a custom assembly function
.execute(client)Execute and return typed results

SQL Utilities

Low-level building blocks for constructing parameterized SQL. All values are safely parameterized.

import { eq, gte, and, where, count, sum, raw, empty } from "@514labs/moose-lib";

Comparison Operators

FunctionSQL Output
eq(col, value)col = value
ne(col, value)col != value
gt(col, value), gte(col, value), lt(col, value), lte(col, value)col > value, etc.
like(col, pattern), ilike(col, pattern)col LIKE pattern, col ILIKE pattern
inList(col, values), notIn(col, values)col IN (...), col NOT IN (...)
between(col, low, high)col BETWEEN low AND high
isNull(col), isNotNull(col)col IS NULL, col IS NOT NULL
filter(col, op, value)Polymorphic — returns empty if value is undefined

Logical Combinators

FunctionDescription
and(...conditions)Combine with AND (empty fragments filtered out)
or(...conditions)Combine with OR
not(condition)Negate a condition

SQL Clauses

FunctionDescription
where(...conditions)WHERE clause (conditions combined with AND)
groupBy(...cols)GROUP BY clause
having(...conditions)HAVING clause
orderBy(...[col, dir])ORDER BY clause
limit(n)LIMIT clause
offset(n)OFFSET clause
paginate(pageSize, page?)LIMIT + OFFSET
select(...cols)SELECT clause
as(expr, alias)Alias an expression

Aggregation Functions

All return an Expr with a fluent .as(alias) method.

FunctionSQL Output
count() / count(col)count(*) / count(col)
countDistinct(col)count(DISTINCT col)
sum(col)sum(col)
avg(col)avg(col)
min(col) / max(col)min(col) / max(col)
sum(MyTable.columns.amount).as("total_amount");countDistinct(MyTable.columns.user_id).as("unique_users");

Core Utilities

FunctionDescription
raw(text)Raw SQL fragment (no parameterization — use only for trusted input)
emptyEmpty SQL fragment (no-op)
join(fragments, sep?)Join fragments with separator (default: ", ")
isEmpty(fragment)Check if a fragment is empty

Helper Functions

timeDimensions

Auto-generate day, week, and month dimension definitions from a date column.

import { timeDimensions } from "@514labs/moose-lib"; dimensions: {  ...timeDimensions(MyTable.columns.timestamp),  // Generates: day (toDate), week (toStartOfWeek), month (toStartOfMonth)}

columnsFromTable

Generate ColumnDef records from a table's schema.

import { columnsFromTable } from "@514labs/moose-lib"; columns: {  ...columnsFromTable(UsersTable, { exclude: ["password_hash"], camelCase: true }),}

filtersFromTable

Generate ModelFilterDef records from a table's schema. Each filter defaults to ["eq"] operator with input type hints derived from the ClickHouse data type.

import { filtersFromTable } from "@514labs/moose-lib"; filters: {  ...filtersFromTable(EventsTable, { include: ["status", "created_at"] }),  status: { column: "status", operators: ["eq", "in"] as const }, // Override}

TableFieldOptions

All three helpers above accept:

PropertyTypeDescription
includestring[]Only include these columns
excludestring[]Exclude these columns
camelCasebooleanConvert snake_case keys to camelCase

deriveInputTypeFromDataType

Map a ClickHouse data type to a UI input type hint ("date", "number", "select", or "text").

import { deriveInputTypeFromDataType } from "@514labs/moose-lib"; deriveInputTypeFromDataType("DateTime"); // "date"

MCP Tool Integration

Auto-generate Claude MCP tools from query models.

registerModelTools

Register all named models as MCP tools on a server.

import { registerModelTools } from "@514labs/moose-lib";import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; const server = new McpServer({ name: "analytics", version: "1.0.0" });registerModelTools(server, [visitsModel, usersModel], queryClient);

This automatically generates Zod schemas from model metadata, converts flat MCP parameters to nested QueryRequest objects, and executes queries with readonly: 2 and max_result_rows enforcement. Only models with a name are registered.

createModelTool

Generate the Zod schema and request builder for a single model when you need more control.

import { createModelTool } from "@514labs/moose-lib"; const tool = createModelTool(visitsModel, {  requiredFilters: ["status"],  maxLimit: 5000,  defaultLimit: 100,  defaults: { dimensions: ["day"], metrics: ["totalVisits"] },}); // tool.schema — Zod shape for server.tool()// tool.buildRequest — Convert flat MCP params to nested QueryRequest

ModelToolOptions

PropertyTypeDescription
requiredFiltersstring[]Filter names whose eq parameter should be required
maxLimitnumberOverride the model's max limit
defaultLimitnumberOverride the model's default limit
defaultsobjectDefault dimensions, metrics, columns, limit

Validation Utilities

createQueryHandler

const handler = createQueryHandler({  fromUrl: typia.http.createValidateQuery<Params>(),  fromObject: typia.createValidate<Params>(),  queryFn: async (params) => { /* custom query logic */ },}); await handler.run(params);await handler.fromUrl(urlString);await handler.fromObject(plainObject);

On this page

defineQueryModelQueryModelConfigDimensionDefMetricDefColumnDefJoinDefModelFilterDefFilter OperatorsQueryModelPropertiesType Inference HelpersMethodsQueryRequestbuildQueryChainable MethodsTerminal MethodsSQL UtilitiesComparison OperatorsLogical CombinatorsSQL ClausesAggregation FunctionsCore UtilitiesHelper FunctionstimeDimensionscolumnsFromTablefiltersFromTableTableFieldOptionsderiveInputTypeFromDataTypeMCP Tool IntegrationregisterModelToolscreateModelToolModelToolOptionsValidation UtilitiescreateQueryHandler
Edit this page
FiveonefourFiveonefour
Fiveonefour Docs
MooseStackHostingTemplatesGuides
Release Notes
Source531
  • Overview
Build a New App
  • 5 Minute Quickstart
  • Browse Templates
  • Existing ClickHouse
Add to Existing App
  • Next.js
  • Fastify
Fundamentals
  • Moose Runtime
  • MooseDev MCP
  • Language Server
  • Data Modeling
Moose Modules
  • Moose OLAP
  • Moose Streaming
  • Moose Workflows
  • Moose APIs & Web Apps
Deployment & Lifecycle
  • Moose Dev
  • Moose Migrate
  • Moose Deploy
Reference
  • API Reference
  • Query Layer
  • Data Types
  • Table Engines
  • CLI
  • Configuration
  • Observability Metrics
  • Help
  • Release Notes
Contribution
  • Documentation
  • Framework