Skip to main content
TQL is the query language used to write ontology queries in TextQL. It is a typed SQL templating language that lets you define reusable, parameterized queries with a small expression layer on top. Use TQL when you want to expose a stable query surface — one that accepts typed parameters, enforces business logic, and always produces consistent SQL.
Parameter descriptions are shown in the UI. When you add -- comments above a param declaration, they appear as help text in the ontology query panel. Use them to document expected formats, example values, and allowed filter keys.

Two File Shapes

TQL files come in two forms.

Plain SQL Template

Use this when the template is essentially SQL with a few direct parameters.
In a plain body, ${...} interpolates a param name directly into SQL.

Expression Body

Use this when you need branching, reusable fragments, matchSet, or semantic-view logic.
An expression body must evaluate to a SqlFragment using sql"..." or sql'' ... ''.

Params

Params are declared in a params { ... } block — one per line, no commas.

Supported Types

Nullability and Defaults

  • ? marks a nullable param. Omitting it resolves to null.
  • Non-nullable params without a default are required.
  • Defaults are supported for scalars and empty lists/sets.

Param Descriptions

-- comments directly above a param declaration are exposed by inspect and shown in the UI as help text.

Expressions

let Bindings

Bindings are evaluated in order. Duplicate names are rejected.

Conditionals

Records and Field Access

SQL Fragments

Use sql"..." for short fragments and sql'' ... '' for multiline SQL.
Critical rule: never quote interpolations yourself.
Nullable params interpolate as NULL, not as an omitted clause. Use if for optional predicates:
List interpolation already adds parentheses:

Builtins

matchSet

The core tool for set-driven SQL structure. Maps each label in a Set<"..."> param to a SQL fragment or record.
Output order follows the authored arm order, not the caller’s order. Repeated values are deduped.

filterWhere

Lowers user-supplied FilterInput values against an authored filter registry.
Supported operators include: equals, not_equals, gt, gte, lt, lte, like, starts_with, ends_with, between, in, not_in, is_null, is_not_null.

concatSep

Concatenates a list of SqlFragment values with a separator. Empty fragments are skipped.

wrap

Adds a prefix and suffix to a fragment, but only if the fragment is non-empty.

isEmpty

Returns true for empty fragments, strings, sets, lists, and null.

map, any, contains

Semantic-View Pattern

The recommended pattern for reusable query surfaces combines metrics, dimensions, and filters params with matchSet and filterWhere.
This pattern gives callers a compact, stable API while keeping all SQL structure in authored code.

Common Gotchas

Use = for param defaults, let bindings, and record fields. Use == / != for expression equality comparisons.
Nullable params interpolate as NULL — they do not remove SQL clauses automatically. Use if or isEmpty for optional predicates.
SELECT ${metrics} fails. Use matchSet or contains to work with set values.
The separator and prefix/suffix must be authored string literals, not params.
In a plain SQL body, ${...} only interpolates a param name. For computed fragments like ${select_expr}, switch to expression-style TQL with sql"...".

Authoring Checklist

Before saving a new .tql file:
  • Params are in params { ... }, one per line, no commas
  • String defaults use double quotes
  • Equality tests use == / !=
  • Optional clauses use if or isEmpty
  • Interpolations are not wrapped in SQL quotes
  • List interpolations are not wrapped in extra parentheses
  • Semantic-view metrics have stable AS ... aliases
  • filters comments document allowed keys and operators