Filters

Filters is also known as Criteria, used to filter an object or a set of objects through a chain of filtering functions. This document gives you a tour from creating some Filter, creating FilterManager, registering filters to FilterManager and calling the filters.

Creating Filter

You can create a filter by either Declaring Filter class that implements an implicit Filter interface, or via FilterManager.create().

Declaring Filter Class

Every filter class must provide a function named apply that returns a Promise. Following example demonstrates a TaxFilter that applies tax of 5% on a specified price and returns the price included tax in result:

class TaxFilter {

    async apply(price) {
        return price * 1.05;
    }
}

or you can alternatively define TaxFilter as a function if you don't want to use ES6 class syntax:

function TaxFilter() {

    this.apply = function(price) {
        return Promise.resolve(price * 1.05);
    }
}

Creating Filter via Filter Manager

Another way (and also better) to create filter is to use FilterManager. Instead of declaring a class, you simply call .create(fn) on FilterManager, in which fn is the filtering function which can be either sync or async. Below is an example of creating a filter equivalent to the class TaxFilter in previous section:

let taxFilter = filterManager.create(async (price) => price * 1.05));

or:

let taxFilter = filterManager.create(price => Promise.resolve(price * 1.05));

Creating Filter Manager

FilterManager provides functionality for both filter registration and filter invocation. To create a new Filter Manager:

const { filters } = require('robo-toolkit');
// or
const _f = require('robo-toolkit').filters;

const filterManager= _f.createManager();

Note that _f is already a static instance of FilterManager, so you can use it as a global FilterManager.

Registering Filters

To register a Filter to FilterManager:

filterManager.add(name, filter, priority);

Parameter explanation:

  • name is name of the filter. Multiple filters having same name will be chained. Once chained, each filter in sequence will use result from the previous filter as parameter to the filtering function.

  • filter is a Filter that is created using one of the methods mentioned in previous section.

  • priority is a number that indicates priority of the filter. The lower number, the higher priority. The filter that has higher priority will be invoked sooner.

Let's register the TaxFilter with a priority of 1:

_f.add('calculate-price', new TaxFilter(), 1);

or alternatively:

_f.add('calculate-price', _f.create(async (price) => price * 1.05)), 1);

Add another filter that discounts the sale price by 10%. This filter should be called prior to tax calculation. We will register it with a higher priority than the TaxFilter, 0 for example:

const discount = 0.1;

_f.add('calculate-price', _f.create(async (price) => price - (price * discount)), 0);

Now we have discount calculation placed on top of tax calculation. Whenever the filter calculate-price is called, discount will be calculated first, then its result will be passed to the tax calculation.

Applying Filters

To apply a filter:

let result = await _f.apply(name, initialValue);

In which:

  • name is name of the filter.

  • initialValue is an object or whatever that will be passed as the only parameter to filtering function of the very first filter in the sequence.

  • result is the final result returned from the last filter in sequence. If there is no registered filters, the initial value will be returned.

Let's invoke the filter calculate-price with an initial price of 100 bucks:

var finalPrice = await _f.apply('calculate-price', 100);

console.log('Final price is: ' + finalPrice);

Output console looks like:

Final price is: 94.50

Last updated