@AppKu/StashKu

@AppKu/StashKu

v1.0.46

Tutorial: Requests: Where (Filters)

StashKu includes the ability to build complex filters that support logical AND and OR conditions, with a variety of comparative operators. Filters can be created using chained and/or function calls, or parsed from a string expression, making it easy to write filters for use in StashKu requests that have where functions.

The Filter object can operate on an array of objects using the test function, which will return only objects matching the criteria.

Getting Started

Filter is the class used within all StashKu GET, PATCH, and DELETE request's .where methods. The .where method will build the request's internal Filter that engines subsequently use to apply conditions to their resources for the purpose of the request.

Take a look at the section Usage on a StashKu Request below to see how you can leverage the .where method.

You can create a new Filter from a string expression:

Filter.parse('{Name} ~~ "Doe" AND Age > 18');

...you can even using logical chain functions together into logical groups:

Filter
    .and('{Name} ~~ "Doe" OR {Name} !~~ "Doey"')
    .and('{Age} > 18');

...or just group in your string:

Filter.parse('({Name} ~~ "Doe" OR {Name} !~~ "Doey") AND Age > 18')

Yes! Nested parenthesis are 100% supported to any depth. ~(˘▾˘~)

If you're feeling traditional, you can build filters in the traditional parameterized approach:

Filter
    .and(Filter
        .or('Name', Filter.OP.CONTAINS, 'Doe')
        .or('Name', Filter.OP.NOTCONTAINS, 'Doey')
    )
    .and('Age', Filter.OP.GREATERTHAN, 18);

Peeking at The Filter

Viewing the filter's expression tree is sometimes tiresome for troubleshooting, that's why the Filter instance fully supports a toString() override that outputs the string expression equivalent of the tree.

This makes looking at a filter defined like this:

let f = Filter
    .or('ID', Filter.OP.EQUALS, 1)
    .or('ID', Filter.OP.EQUALS, 2)
    .or(Filter
        .and('Name', Filter.OP.ISNULL)
        .and('Age', Filter.OP.GREATERTHAN, 24)
        .or('Products', Filter.OP.IN, [1, 2, 3])
    );

... into a string like this:

{ID} EQ 1 OR {ID} EQ 2 OR (({Name} ISNULL AND {test4} GREATERTHAN 24) OR {Products} IN [1, 2, 3])

Best of all, you can Filter.parse the toString'd value back into a new Filter instance.

Filtering Object Arrays

In this example where we're going to filter an array of simple objects using the test() function, searching for records with the Name property containing the value "Doe":

let contacts = [
    { Name: 'John Doe', Age: 22},
    { Name: 'Marcus Inger', Age: 45},
    { Name: 'Gilli Mokes', Age: 18},
    { Name: 'Susan Doe', Age: 21},
    { Name: 'Sally Sue', Age: 55}
];
let results = Filter
    .and('Name', Filter.OP.CONTAINS, 'Doe')
    .test(...contacts);
console.log(results);
// [ { Name: 'John Doe', Age: 22}, { Name: 'Susan Doe', Age: 21} ]

This is similar to using a JavaScript array's built-in filter method, but in this case we are using a portable and cross-domain filter that is standardized.

Usage on a StashKu Request

Filters power StashKu requests, and are used by engines to translation conditional expressions into their resource interface. Requests accept filters in their where function, which is only on GetRequest, DeleteRequest and PatchRequest instances.

The where functions accept a Filter string expression:

await myStash.get(r => r
    .where('{Name} ~~ "Doe" OR {Name} !~~ "Doey"')
);

... or a Filter instance:

let myConditions = Filter.and('Name', Filter.OP.CONTAINS, 'Doe');
await myStash.delete(r => r
    .where(myConditions)
);

... or a callback that lets you build on a filter already set on the request. This can be useful for cross-domain StashKu requests.

let myConditions = Filter.and('Name', Filter.OP.CONTAINS, 'Doe');
await myStash.patch(r => r
    .where(myConditions)
    .where((f, orig) => orig.or('{Name} ~~~ "Doey"'))
);

A cross-domain StashKu request, for example, could be a request passed from the fetch engine to a StashKu instance on the server being served up on express- where you want the server wants constrain the results (let's say... only where the DateDeleted property is null) could look like this:

let inReq = StashKu.fromObject(httpReq);
await myStash.patch(inReq
    .where((f, orig) => Filter.and(orig).and('{DateDelete} ISNULL'))
);

Want to see this in action? Check out the node+browser demo.

Logic

The following logical conditions are available on Filter objects:

Property Value Function
Filter.LOGIC.AND "and" Filter.and(...)
Filter.LOGIC.OR "or" Filter.or(...)

Operators

The following operators are available for use in an expression. All engines built-into StashKu support these operations. In string expressions, you should use the uppercase value or alias, though the property name will work as well.

Property Value Aliases (String Expressions)
Filter.OP.EQUALS "eq" "=="
Filter.OP.NOTEQUALS "neq" "!="
Filter.OP.ISNULL "isnull"
Filter.OP.ISNOTNULL "isnotnull"
Filter.OP.LESSTHAN "lt" "<"
Filter.OP.LESSTHANOREQUAL "lte" "<="
Filter.OP.GREATERTHAN "gt" ">"
Filter.OP.GREATERTHANOREQUAL "gte" ">="
Filter.OP.STARTSWITH "startswith"
Filter.OP.ENDSWITH "endswith"
Filter.OP.CONTAINS "contains" "~~"
Filter.OP.DOESNOTCONTAIN "doesnotcontain" "!~~"
Filter.OP.ISEMPTY "isempty"
Filter.OP.ISNOTEMPTY "isnotempty"
Filter.OP.IN "in"
Filter.OP.NOTIN "nin"

Looking for More?