A single clause
The smallest unit of a query is a clause:<property> <operator> <value>. The property name is the same name used elsewhere in Twine for that field - see Employee for the full list of properties on the most common entity. The operator is required: first_name "John" is a parse error.
Comparison operators
Equality and inequality (
=, !=) are type-tolerant: employee_no = 123 matches a stored "123" and vice versa. This is intentional, because property values arrive from many different source systems and can land in storage with varying types.
Value types
The parser recognises the following value forms:Strings
Quoted strings ("John") are the canonical form. Use quotes whenever the value could be confused with another type, contains a comma, or begins or ends with whitespace.
Naked strings are the fallback: anything in value position that does not match a typed form is captured as a string. It ends at the next comma, before the next AND or OR, or at a ) that closes a group. note = hej baberiba parses cleanly, with the value hej baberiba, and status != inactive AND employee_no = "9550" is two clauses. To keep a standalone and or or inside a value, quote it: department = "Sales and Marketing". Parentheses inside a value are kept when they are balanced, so department = Sales (EU) works unquoted.
Quoted strings have no escape syntax. The first " after the opening quote ends the string.
Numbers
Integers are bare digits. Floats accept both. and , as the decimal separator. A bare negative integer such as -5 is read as the text "-5": = and != still match a stored -5, but > and < compare it as text. Write it as a float (-5.0) to compare it as a number.
Booleans
true and false, lowercase only. Anything else (True, 1, yes) is treated as a string.
Dates
The canonical date form isYYYY-MM-DD. The separator can be a space or omitted entirely, so 2024 01 01 and 20240101 are also accepted. Invalid calendar dates such as 2024-02-30 cause the parse to fail.
Blank
blank, nil, and null are equivalent and all parse to the same “no value” sentinel. field = blank matches when the property is missing from the entity entirely, when its value is null, or when its value is an empty list. field != blank is the negation. Other operators against blank (such as >) are not meaningful and return no match.
Lists
Bracketed, comma-separated, and used only within:
[1, 2.5] works).
Filtering by when a value was valid
Each clause runs against an entity’s dated property timeline. An optional, <date constraint> after the value decides which entries the comparison runs against:
today is resolved each time the query runs, so a saved query stays relative. It is only a keyword in the suffix; as a value, first_name = today compares against the text today.
Worked salary-history examples:
Combining clauses
Clauses can be combined withAND and OR, and negated with NOT. The keywords match in any case, so and works as well as AND. NOT binds tightest, then AND, then OR, so:
first_name = "John" OR (first_name = "Jane" AND salary_amount > 50000, today). Parentheses override precedence:
NOT goes in front of a clause or a parenthesised group. It is the way to say “does not match” for ~=, which has no negative form of its own:
NOT asks whether no entry of the field matches. On a field with a history that is not the same as !=, which asks whether some entry differs: NOT salary_amount = 1, * fails if the salary was ever 1, while salary_amount != 1, * passes if it was ever anything else. An employee who has no value for the field at all satisfies every NOT.
Filtering by integration mapping
A clause can test an employee’s mapping to one system integration instead of a property. Name the integration by its id, the one in the address of its page in Twine:
Mapping clauses combine with property clauses like any other clause:
= blank. So mapping(<id>).status != active leaves unmapped employees out, and NOT mapping(<id>).status = active includes them.
A misspelled field or status, or an id that is not an integration id, fails the parse instead of matching nothing. A mapping has no history, so a mapping clause takes no valid_from suffix.
Worked examples
false, not the string "false".
John, Joel and joak match (the match ignores case), Jonathan does not.
Where this query language is used
The same syntax is accepted in every place that filters dated-property-backed entities:- The Employee list filter in Backoffice.
- The Backoffice system-data employee browser.
- The system-integration sync-preview filter.
- The organizational unit list filter.
- The
queryargument on the MCPlist_employeestool. - The “Load employees by query” flow step.
- The employee report filter.
Limitations and gotchas
NOTis not!=. See Combining clauses:NOTnegates the clause over the whole field,!=compares each entry.- An unquoted value ends at a comma, at
ANDorOR, or at a)that closes a group. Quote a value that contains a standaloneandoror. Parentheses inside a value are kept when they are balanced, sodepartment = Sales (EU)works unquoted. - Quoted strings have no escape syntax. A literal
"cannot appear inside a quoted string. - Typos in numeric or date values degrade to strings. The query still parses, but never matches the property’s real value.
- A clause without a date suffix ignores dated entries. Use
, todayfor the current value; see Filtering by when a value was valid. - Bare negative integers are text.
age > -5compares as text; write-5.0. - Property names accept ASCII plus the Latin-1 supplement (
Ä,Å,Ö,ø,ñ, and so on). Other Unicode scripts cannot be used as property names, though they are valid inside quoted string values. - Invalid calendar dates fail the parse rather than silently degrading -
2024-02-30returns an error. - The
idfield of a dated property is not addressable from this language. It exists in the data model (see properties with multiple simultaneous values) but the text query syntax always considers everyidfor a given key.