Filter Context
The with parameter assigns values to the variables a
filter expression
references with $NAME. Agility calls this the filter context.
filter_context_token = [ assignment , { "|" , assignment } ] ;
assignment = "$" , NAME , "=" , value , { "," , value } ;
value = ? any run of characters other than "," and "|" ? ;
Assignment
Assignments are separated by |; the values within one assignment are separated
by ,:
&with=$Scope=Scope:0,Scope:1,Scope:2
&with=$Story=Story:3|$Scope=Scope:0,Scope:1,Scope:2
A variable holding several values behaves as a value list wherever it is used,
so Scope=$Scope against the assignment above means "Scope is any of
Scope:0, Scope:1, Scope:2".
Worked Example
GET /rest-1.v1/Data/Epic
?where=AssetState!='Closed';Scope=$Scope;-SuperAndUp[Scope=$Scope]
&with=$Scope=Scope:0,Scope:1,Scope:2
$Scope is referenced twice — once at the top level and once inside a nested
inline filter — from a single assignment. The query reads "open Epics in any of
these three projects that are not contained by another Epic in those same
projects", i.e. the top-level Epics of that project set.
That reuse is the point of the feature. Without it you would repeat the OID list in both places, and the two copies would drift.
with are not quoted — unlike values in whereThis is the difference that catches people. In where, every value is a quoted
string: where=ToDo='0'. In with, values are bare: with=$Scope=Scope:0.
The reason is in the grammar's own preamble: "The actual implementation of this
grammar is done with simple token splitting." V1FilterContext.g has to model
that with a lexer mode — CONTEXT_VALUE is defined as ~(',' | '|')*, any run
of characters that is not a comma or a pipe. Quote marks are not delimiters
there; they are just more characters in the value.
So with=$Scope='Scope:0' assigns the eight-character string 'Scope:0',
apostrophes included, and the filter that compares against it silently matches
nothing.
Two consequences of the same token-splitting rule:
- A value may contain spaces, colons, quotes and equals signs. Only
,and|terminate it. (URL-encoding rules still apply on top of this — encode the parameter value as usual.) - A value cannot contain a comma or a pipe, and there is no escape
mechanism. If a value you need contains either character,
withcannot carry it; inline the value in the filter expression instead, where quoting exists.
What Can Be Assigned
The shipped examples all assign OIDs (Scope:0, Story:3). The grammar itself
places no constraint on the value beyond the delimiter rule, so plain scalars
also parse. Whether a given variable is meaningful in a given comparison depends
on the attribute it is compared against; that is not something the grammar
constrains, and no shipped example demonstrates a non-OID assignment. Treat
non-OID values as unverified.
$ on its own — the context asset — is not assignable through with. It is
supplied by the query itself. V1FilterContext.g only produces
VARIABLE_NAME, which requires a name after the $.
Where It Applies
Unlike where, filter context is applied to every query shape, including
single-asset requests: AddQueryFilterContext is called from DoAssetQuery,
DoAssetTypeQuery and DoHistoricalAssetQuery alike. That matters because a single-asset request can still
carry a sel containing inline filters that reference variables.
Reserved Variables
Two variable names are supplied by the server rather than by your with
parameter:
-
$on its own is the asset itself. In a filter that is evaluated against a concrete asset — a bracket filter on an attribute path, or the valid-values filters the schema defines —$resolves to that asset:GET /rest-1.v1/Data/Scope/1067?sel=Members[Scopes=$].Namereturns the members whose
ScopescontainScope:1067. A top-levelwherehas no asset to refer to, and sending$there is a server error. -
$Searchis the current text search's result set. When a request carriesfind, the matched asset IDs are bound to$Search, and a filter may reference them:GET /rest-1.v1/Data/Story?find=login&findin=Name&where=ID=$Search&sel=Name&page=50,0The name is only defined while a
findis present. Its value is the matched set itself, so the practical use is referencing search results from a relation's filter rather than the root asset's.
Assigning either name yourself in with is not supported — treat both as
reserved. A third server-supplied name, #ContextOid, belongs to the Bulk
API's create commands rather than to filters — see
aliases and projection.
Errors
A with value that fails to parse produces 400 Bad Request with the message
Invalid WITH parameter. Note that because almost anything lexes as a
CONTEXT_VALUE, a malformed assignment is far more likely to produce a
successful query that matches nothing than an error. If a filter using a
variable returns an empty set, check the with value for stray quotes first.
The query.v1 Equivalent
query.v1 carries the same concept as a mapping rather than a token, which
removes the quoting trap entirely:
{
"from": "Epic",
"select": ["Number", "Name"],
"filter": ["AssetState!='Closed';Scope=$Scope;-SuperAndUp[Scope=$Scope]"],
"with": {
"Scope": ["Scope:0", "Scope:1", "Scope:2"]
}
}
The parser reads the mapping keys verbatim, so whether the key needs the
leading $ is decided downstream — and is not verifiable from the parser
alone. The
example above omits it, matching how the reference in the filter expression
supplies the $. If a query.v1 filter using a variable returns nothing, try
the key both ways.