Skip to main content

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.

warning
Values in with are not quoted — unlike values in where

This 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, with cannot 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=$].Name

    returns the members whose Scopes contain Scope:1067. A top-level where has no asset to refer to, and sending $ there is a server error.

  • $Search is the current text search's result set. When a request carries find, 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,0

    The name is only defined while a find is 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.