Query Language

A complete reference for the Pomavo query DSL, covering filtering, sorting, aggregation, references, date math, and bulk mutations with worked examples.

Overview

The Pomavo query language, or DSL, is a structured way to find and act on tickets. The same language powers Search, Saved Queries, reports, and bulk mutations. A query reads left to right as a filter, optionally followed by sorting, grouping/projection, or a mutation clause.

dsl
template = "Bug" and status != "Done"
order by created_at desc

The same editor with autocompletion is available everywhere the DSL is accepted, and these examples render with the exact highlighting you see in the product.

The DSL editor with autocompletion, available everywhere search is accepted.

Anatomy of a Query

A query is built from a few kinds of pieces:

  • Fields: what you filter on. Built-in fields like status, template, assignee, created_at, or any custom field by name.
  • Operators: how you compare, including =, contains, in, between, and more.
  • Values: strings ("In Progress"), numbers (5), dates (d'today'), references (@me), or another field (
    quot;Story Points"
    ).
  • Clauses: order by, group by, return, limit/offset, and mutation clauses.
dsl
priority = "High" and assignee = @me
order by created_at desc
limit 25

Field Names

Reference a field by its name. Names with spaces or special characters must be quoted:

dsl
status = "In Progress" and "Story Points" >= 5

Field names are case-insensitive. Built-in fields such as status, template, created_at, assignee, and id are recognized everywhere.

Comparison Operators

OperatorMeaning
=Equal to
!=Not equal to
> >= < <=Greater / less than for numbers and dates
between ... and ...Inclusive range
dsl
priority = "High"
dsl
"Story Points" >= 3 and "Story Points" <= 8
dsl
created_at between d'-30d' and d'today'

Text Matching

OperatorMatches
contains / not containsSubstring anywhere in the value
starts withValue begins with the text
ends withValue ends with the text
likeWildcard match: * matches any run and ? matches a single character
dsl
title contains "login" and description not contains "duplicate"
dsl
title starts with "[URGENT]"
dsl
"Branch Name" like "release/*"

Set Membership

dsl
status in ("To Do", "In Progress", "In Review")
dsl
assignee not in (@me, @alice, @bob)

Presence

Check whether a field has a value at all:

dsl
assignee is empty
dsl
"Due Date" is not empty and status != "Done"

Logical Operators & Grouping

Combine conditions with and, or, and not. Use parentheses to control precedence:

dsl
(template = "Bug" or template = "Incident") and assignee = @me and status not in ("Done", "Closed")
dsl
not ("Due Date" is empty) and priority in ("High", "Critical")

References

Instead of a literal value, you can reference a user or another field:

  • @me: the current user, resolved at query time, which is great for saved queries shared across a team
  • @username: a specific user by username
  • $field or
    quot;Field Name"
    : the value of another field on the same ticket
dsl
assignee = @me and author != @me
dsl
"Actual Hours" > 
quot;Estimated Hours"

Date Literals

Dates are written with the d'...' form:

  • Absolute: d'2025-01-15'
  • Keywords: d'today', d'now'
  • Relative: d'-7d' for seven days ago, d'now-1w', d'2y3m4d' to combine years, months, weeks, and days
dsl
created_at >= d'-7d' and created_at < d'today'
dsl
"Due Date" between d'today' and d'now+2w'

Sorting & Pagination

dsl
status = "In Progress"
order by priority desc, created_at asc
limit 50
offset 100
  • order by <field> [asc|desc]: sort by one or more fields
  • order by <field> numeric: sort a text field as numbers
  • order by <field> custom(a, b, c): sort by an explicit order, e.g. a workflow sequence
  • limit N / offset N: page through results
dsl
status
order by status custom("To Do", "In Progress", "In Review", "Done")

Aggregation & Projection

Go beyond filtering to compute summaries with group by and return:

dsl
status != "Done"
group by assignee
return assignee, count() as open_tickets
order by open_tickets desc
  • group by <field>[, <field>]: bucket tickets by one or more fields
  • return <expr> [as <alias>][, ...]: choose each row's output; supports arithmetic (+ - * /) and functions
dsl
group by template
return template, count() as total, avg(
quot;Story Points"
) as avg_points

Functions

FunctionReturns
now()The current date and time
today()The current date
startOfDay(date)The start of the given day
startOfWeek(date)The start of the given week
length(value)The length of a value
count() / count(expr)Number of tickets in a group
sum(expr)Sum of a numeric expression
avg(expr)Average of a numeric expression
min(expr) / max(expr)Minimum / maximum of an expression
dsl
group by assignee
return assignee, sum(
quot;Story Points"
) as committed, max(created_at) as latest

Comments

Annotate long queries with # or -- line comments:

dsl
# Open, unassigned bugs raised this week
template = "Bug" and assignee is empty and created_at >= d'-7d' -- last 7 days only

More Worked Examples

A grab-bag of everyday queries:

dsl
# Everything assigned to me that isn't finished
assignee = @me and status not in ("Done", "Closed")
order by priority desc
dsl
# Stale tickets: untouched for over 30 days and still open
status not in ("Done", "Closed") and updated_at < d'-30d'
order by updated_at asc
dsl
# High-priority work due this week
priority in ("High", "Critical") and "Due Date" between d'today' and d'now+1w'
dsl
# Bugs whose estimate was exceeded
template = "Bug" and "Actual Hours" > 
quot;Estimated Hours"
dsl
# Workload by assignee for the current sprint
"Sprint" = "Sprint 24"
group by assignee
return assignee, count() as tickets, sum(
quot;Story Points"
) as points order by points desc

Bulk Mutations

The DSL can also change the tickets a query matches. A filter selects the tickets; a mutation clause applies the change to all of them. Mutations run as a background job, so large updates do not block the UI.

Mutations apply to every ticket the filter matches. Run the query as a plain search first to confirm the result set before turning it into a mutation.

ClauseEffect
set <field> = <value>Update field values on matched tickets
create <template> set ...Create a new ticket from a template
link <value> to (<query>)Link matched tickets to the tickets in a sub-query
unlink <value> / unlink allRemove links
comment <value>Add a comment to matched tickets

Updating Fields

Append a set clause to any filter to update the matches:

dsl
status = "Done" and resolution is empty
set resolution = "Fixed"

Set multiple fields at once, and compute values from existing ones:

dsl
template = "Bug" and priority = "Critical"
set status = "In Progress", assignee = @me
dsl
"Sprint" = "Sprint 23" and status != "Done"
set "Sprint" = "Sprint 24"

Creating Tickets

dsl
create "Bug"
set title = "Investigate flaky checkout test", priority = "High", assignee = @me

Linking & Unlinking

Link every matched ticket to the tickets returned by a sub-query:

dsl
template = "Bug" and "Sprint" = "Sprint 24"
link "blocks" to (template = "Release" and title = "v2.0")
dsl
status = "Closed"
unlink all

Commenting in Bulk

dsl
status = "In Review" and updated_at < d'-3d'
comment "Friendly nudge: this has been waiting for review for over 3 days."

Where to Next