4minitz/4minitz

View on GitHub
imports/search/TopicsFilter.js

Summary

Maintainability
C
1 day
Test Coverage
import { Meteor } from 'meteor/meteor';
import { _ } from 'meteor/underscore';

import { ItemsFilter } from './ItemsFilter';

import { TOPIC_KEYWORDS } from './FilterKeywords';

export class TopicsFilter {

    constructor() {
        this.isCaseSensitive = false;
        this.itemsFilter = new ItemsFilter();
    }

    filter(docs, parser) {
        if (!parser) { throw new Meteor.Error('illegal-state', 'Please inject a query parser.'); }
        if (!docs) { docs = []; }


        this.isCaseSensitive = parser.isCaseSensitive();
        return docs.filter(doc => {
            return this.docMatchesSearchTokens(doc, parser.getSearchTokens())
                && this.docMatchesLabelTokens(doc, parser.getLabelTokens())
                && this.docMatchesFilterTokens(doc, parser.getFilterTokens());
        });
    }

    docMatchesSearchTokens(doc, searchTokens) {
        for (let i=0; i < searchTokens.length; i++) {
            let token = this._toUpper(searchTokens[i]);
            let subject = this._toUpper(doc.subject);

            let hasMatchingInfoItems =
                this.itemsFilter.filterWithParams(doc.infoItems, this.isCaseSensitive, [token]).length > 0;

            if (
                (subject.indexOf(token) === -1
                && !hasMatchingInfoItems)
            ) {
                return false;
            }
        }
        return true;
    }

    _toUpper(str) {
        return (this.isCaseSensitive) ? str : str.toUpperCase();
    }


    docMatchesLabelTokens(doc, labelTokens) {
        for (let i=0; i < labelTokens.length; i++) {
            let token = labelTokens[i];
            let hasMatchingInfoItems =
                this.itemsFilter.filterWithParams(doc.infoItems, this.isCaseSensitive, [], [token]).length > 0;
            if (!hasMatchingInfoItems) {
                return false;
            }
        }
        return true;
    }

    docMatchesFilterTokens(doc, filterTokens) {
        for (let i=0; i < filterTokens.length; i++) {
            let filter = filterTokens[i];

            switch (filter.key) {
            case TOPIC_KEYWORDS.IS.key:
            {
                if (!this.constructor._docMatchesKeyword_IS(doc, filter.value)) {
                    return false;
                }
                break;
            }
            case TOPIC_KEYWORDS.HAS.key:
            {
                if (!this._docMatchesKeyword_HAS(doc, filter.value)) {
                    return false;
                }
                break;
            }
            case TOPIC_KEYWORDS.USER.key:
            {
                if (!this._docMatchesKeywords_USER(doc, filter)) {
                    return false;
                }
                break;
            }
            case TOPIC_KEYWORDS.DO.key:
            {
                break;
            }
            default: throw new Meteor.Error('illegal-state', `Unknown filter keyword: ${filter.key}`);
            }
        }

        return true;
    }

    _docMatchesKeywords_USER(doc, filter) {
        if (!doc.responsibles) { return false; }
        let respStr = doc.responsibles.reduce((acc, resp) => { return acc + resp; }, '');
        return ( (filter.ids && _.intersection(doc.responsibles, filter.ids).length > 0)
                    || (filter.value && this._toUpper(respStr).indexOf(this._toUpper(filter.value)) !== -1) );
    }


    static _docMatchesKeyword_IS(doc, value) {
        switch (value) {
        case 'uncompleted':
        case 'open':
            return doc.isOpen;
        case 'completed':
        case 'closed':
            return !doc.isOpen;
        case 'new':
            return doc.isNew;
        default: throw new Meteor.Error('illegal-state', `Unknown filter value: ${value}`);
        }
    }

    _docMatchesKeyword_HAS(doc, value) {
        switch (value) {
        case 'item':
            return doc.infoItems.length > 0;
        case 'info':
        case 'action':
        {
            let items = this.itemsFilter.filterWithParams(
                doc.infoItems,
                this.isCaseSensitive,
                [],
                [],
                [{key: 'is', value: value}]);
            return items.length > 0;
        }
        default: throw new Meteor.Error('illegal-state', `Unknown filter value: ${value}`);
        }
    }


}