tally-react takes this text, tally-ai asks the model to answer in it, and useViewUrl writes it to the URL. Every place that shows or stores a filter uses the same language.
Parse, print, execute
parse.ts
parseQuery(text, schema) returns:
Parsing never throws. A query with errors still returns everything that parsed, so a half-typed filter keeps the clauses that are already valid.
printQuery(query, schema) prints the canonical form. plan is pro or team prints as plan in (pro, team), and mrr > 2k as mrr > 2000. execute(rows, query, schema) runs a query over an array and returns the rows, total, matched, and groups, aggregates and facets when asked.
Names and values
Columns resolve by id, label or alias, ignoring case. Enum values resolve by value or label.
A year or a month used with
is covers the whole period, so renewal is 2026-01 matches every day of January. Relative ranges resolve against the grid’s today, which follows the time zone of the format context.
Clauses
Bare words outside a condition search every searchable column. A search is case insensitive. In memory it matches the formatted text of a value, so
acme finds Acme Corp. The SQL adapters in tally-server and tally/laravel match the stored value.
sort by without a direction sorts numbers and dates descending and everything else ascending. group by groups by the column. The granularity of a date group is part of the view, not the text.
The query language reference lists every operator and phrasing with its canonical form, parsed from the code.
Flags
A flag, writtenis:name, is a named predicate the language does not define. The grid resolves is:changed itself: it matches rows with cells changed by a live patch. Every other name goes to the flags option of the grid, a function from a flag name and a row to a boolean. A flag nobody resolves matches nothing.
The AST
A query is plain data. Build one in code with the AST constructors and print it as text.ast.ts
and and or flatten nested nodes of the same type and drop undefined. not of a condition flips its operator when there is an opposite, so not(plan is free) becomes plan is not free.
Autocomplete
suggest(text, cursor, schema, options?) returns completions for the clause under the cursor: columns, operators that fit the column’s kind, values and directives. Pass facets to suggest the values present in the data, examples for example queries, and limit, which defaults to 8. Each suggestion carries the range of text it replaces.