Difference between revisions of "Filters"
| Line 250: | Line 250: | ||
You can create a filter which sorts using "sort" like so: | You can create a filter which sorts using "sort" like so: | ||
<syntaxhiglight lang="js"> | |||
{ | { | ||
"sort":{ | "sort":{ | ||
| Line 256: | Line 257: | ||
} | } | ||
} | } | ||
</syntaxhighlight> | |||
= Filter functions = | = Filter functions = | ||
Revision as of 16:47, 29 January 2024
Filters are a query-like mechanism for filtering out results from a list endpoint. At their core, they are textual and support a set of arguments.
Filter examples
A textual filter with arguments is like so:
(UserId=? or UserId=?) and CreatedUtc>?
It is not case sensitive. Filters in the permission system do not support these ? arguments (as it wouldn't know where to bind the value from).
Typically you'll see this textual form of filter inside a Where() call in the C# API:
uint userId = 14;
var listOfThingsByThisUser = await Where("UserId=?").Bind(userId).ListAll(context);
.Bind() is used to bind the actual value of an argument. Values are bound in this way such that the filter string is a constant and can benefit from being precompiled. Indeed, the whole filter system is built to be entirely non-allocating, as the Bind calls internally set your provided value onto an compiled object field, with that object originating from a pool for the given cached filter.
JS filter notation
Filters can also be constructed by the frontend, most often by Loop. In this scenario, a convenience filter notation is also available - it'll take the object notation you provide, and then convert it into the textual format with arguments. Here's some examples:
<Loop over="page" filter={
{
where: {
userId: 14
}
}
}>
{page => { return <p>{page.url}</p>; }}
</Loop>
import webRequest from 'UI/Functions/WebRequest';
webRequest("page/list", {
where: {
userId: 14
}
}).then(response => {
// response.json contains the set of pages made by user #14
})
The filter object itself:
{
where: {
userId: 14
}
}
#Operators can be used by passing an object:
{
where: {
userId: {
greaterThan: 14
}
}
}
Or statements are represented with an array:
{
where: [{
userId: 14
},
{
userId: 16
}]
}
And statements are performed by providing multiple field values:
{
where: {
userId: 14,
createdUtc: {
greaterThan: yesterday /* yesterday is a JS Date */
}
}
}
If you need more expressive power, you can also directly specify the query and args:
{
query: "UserId=?",
args: [14]
}
Query/args being passed in to webRequest and Loop:
import webRequest from 'UI/Functions/WebRequest';
webRequest("page/list", {
query: "UserId=?",
args: [14]
}).then(response => {
// response.json contains the set of pages made by user #14
})
<Loop over='page' filter={{query: "UserId=?",
args: [14]}}> ...
</Loop>
Operators
Filters support a variety of operators for comparisons:
- Greater than
* Field>? (query notation)
* {greaterThan: x} (JS notation)
- Less than
* Field<? (query notation)
* {lessThan: x} (JS notation)
- Greater than or equal
* Field>=? (query notation)
* {greaterThanOrEqual: x} (JS notation)
* {geq: x} (JS notation)
- Less than or equal
* Field<=? (query notation)
* {lessThanOrEqual: x} (JS notation)
* {leq: x} (JS notation)
- Equals
* Field=? (query notation)
* x (JS notation)
* {equals: x} (JS notation)
- Not
* Field!=? (query notation)
* !( .... ) (query notation)
* {not: x} (JS notation)
- Starts with (textual values only)
* Field startsWith ? (query notation)
* {startsWith: x} (JS notation)
- Ends with (textual values only)
* Field endsWith ? (query notation)
* {endsWith: x} (JS notation)
- Contains (textual values only)
* Field contains ? (query notation)
* {contains: x} (JS notation)
Arrays
If you provide an array of values you must tell the query system that you are doing so by surrounding your ? arg with square brackets, like this:
Name=[?]
This syntax exists such that the precompiled filter is ready to receive a set of values rather than just one.
If you're doing this in C# you can then bind any IEnumerable like so, provided its data type matches that of the target field:
var nameList = new List<string>() { "Dave", "Steve" };
var resultsWithEitherName = await Where("Name=[?]").Bind(nameList).ListAll(context);
From javascript you can just pass an array inside your args like so:
{
"query": "Name=[?]",
"args": [
["Dave", "Steve"]
]
}
Virtual Fields
Virtual Fields can be used inside filter query strings as well just by simply using their name. The value is always the uint IDs. So for example if we want to get all pages tagged with "hello", first we need to get the ID of the tag "hello" (which we'll say is tag #4) and then from there can use it as either an array or a number as-is:
{
query: "Tags contains ?", // Results must have tag #4 on them, but can have any other tags too
args: [
4
]
}
{
query: "Tags=?", // Results must have exactly 1 tag and it must be tag #4
args: [
4
]
}
You can query with an array as well, and like above there are two variants:
{
query: "Tags contains [?]", // Results must have tag #4 and tag #5 on them but can have any other tags too
args: [
[4, 5]
]
}
{
query: "Tags=[?]", // Results must have exactly tags #4 and #5 and no others
args: [
[4, 5]
]
}
Sorting
You can create a filter which sorts using "sort" like so:
<syntaxhiglight lang="js"> {
"sort":{
"field": "name",
"dir": "desc" // or asc
}
} </syntaxhighlight>
Filter functions
Most often seen in the permission system. These are functions used within a query filter. Filter functions are generic and can also be custom defined by installable modules if you need another. Example code which adds a filter function can be seen on the context extensions page. Variations of UserPermits ("CompanyPermits" etc) are quite common.
- IsSelf()
- HasUserPermit()
- HasRolePermits()
- IsIncluded()
- On(...)
Todo: describing the above, particularly On and IsIncluded