model/Filter.js

import { checkDefined } from '../lib/check'

const FILTER_COMPARATORS = {
    /**
     * @function equals
     * @memberof module:model.Filter.prototype
     * @returns {Filter} Returns the modified filter for chaining
     *
     * @description
     * This method can be used to add a equals filter value
     */
    equals: 'eq',
    /**
     * @function like
     * @memberof module:model.Filter.prototype
     * @returns {Filter} Returns the modified filter for chaining
     *
     * @description
     * This method can be used to add a like filter value
     */
    like: 'like',
    /**
     * @function ilike
     * @memberof module:model.Filter.prototype
     * @returns {Filter} Returns the modified filter for chaining
     *
     * @description
     * This method can be used to add a ilike filter value
     */
    ilike: 'ilike',
    /**
     * @function
     * @memberof module:model.Filter.prototype
     * @returns {Filter} Returns the modified filter for chaining
     *
     * @description
     * This method can be used to add a ne filter value
     */
    notEqual: 'ne',
    /**
     * @function
     * @memberof module:model.Filter.prototype
     * @returns {Filter} Returns the modified filter for chaining
     *
     * @description
     * This method can be used to add a in filter value
     */
    in: 'in',
    /**
     * @function
     * @memberof module:model.Filter.prototype
     * @returns {Filter} Returns the modified filter for chaining
     *
     * @description
     * This method can be used to add a tokens filter value
     */
    token: 'token',
    /**
     * @function
     * @memberof module:model.Filter.prototype
     * @returns {Filter} Returns the modified filter for chaining
     *
     * @description
     * This method can be used to add a !in filter value
     */
    notIn: '!in',
    /**
     * @function
     * @memberof module:model.Filter.prototype
     * @returns {Filter} Returns the modified filter for chaining
     *
     * @description
     * This method can be used to add a !token filter value
     */
    nToken: '!token',
}

/**
 * Filter class that can be used to build api endpoint filters using a semi-natural language style.
 *
 * @memberof module:model
 */
class Filter {
    /**
     * @constructor
     * @param {Function} addFilterCallback Callback that will be used to notify Filters that the filter is completed
     * so it can be added to the list of filters.
     */
    constructor(addFilterCallback) {
        this.addFilterCallback = addFilterCallback
        this.propertyName = 'name'
        this.comparator = 'like'
        this.filterValue = undefined
    }

    /**
     * @param {String} propertyName Property name that the filter should be applied on.
     * @returns {Filter}
     */
    on(propertyName) {
        checkDefined(propertyName, 'Property name to filter on')

        this.propertyName = propertyName
        return this
    }

    /**
     * Utility function used to get the query parameter value in a DHIS2 metadata filter format that can be
     * send to the api. This returned value is appended to the `filter=` part of the query.
     *
     * @private
     * @note {warning} Usually not used directly and only used by Filters to create the query param values.
     *
     * @returns {string} The query param value to be appended to `filter=`
     */
    getQueryParamFormat() {
        return [this.propertyName, this.comparator, this.filterValue].join(':')
    }

    /**
     * @static
     *
     * @param {Function} addFilterCallback Callback to be called when the filter is completed.
     *
     * @returns {Filter} A instance of the Filter class that can be used to create
     * filters.
     *
     * @description
     * Create a filter instance
     */
    static getFilter(addFilterCallback) {
        return new Filter(addFilterCallback)
    }

    /**
     * Utility function to add an operator with filterValue
     * @param {*} operator to use
     * @param {*} filterValue to filter on
     */
    operator(operator, filterValue) {
        checkDefined(operator, 'operator')
        checkDefined(filterValue, 'filterValue')
        this.comparator = operator
        this.filterValue = filterValue
        return this.addFilterCallback(this)
    }
}

// Add the filters to the Filter prototype
Object.keys(FILTER_COMPARATORS).forEach(filter => {
    Object.defineProperty(Filter.prototype, filter, {
        value: function filterGetter(filterValue) {
            checkDefined(filterValue, 'filterValue')

            this.comparator = FILTER_COMPARATORS[filter]
            this.filterValue = [
                FILTER_COMPARATORS.in,
                FILTER_COMPARATORS.notIn,
            ].includes(this.comparator)
                ? `[${filterValue.join(',')}]`
                : filterValue

            return this.addFilterCallback(this)
        },
    })
})

export default Filter