UNPKG

forest-express-sequelize

Version:

Official Express/Sequelize Liana for Forest

185 lines (180 loc) 6.26 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); require("core-js/modules/es.promise.js"); require("core-js/modules/es.string.trim.js"); require("core-js/modules/es.array.iterator.js"); var _forestExpress = require("forest-express"); var _operators = _interopRequireDefault(require("../utils/operators")); var _errors = require("./errors"); const { getReferenceSchema, getReferenceField } = require('../utils/query'); function FiltersParser(modelSchema, timezone, options) { var _this = this; this.OPERATORS = _operators.default.getInstance(options); this.operatorDateParser = new _forestExpress.BaseOperatorDateParser({ operators: this.OPERATORS, timezone }); this.perform = async function (filtersString) { return _forestExpress.BaseFiltersParser.perform(filtersString, _this.formatAggregation, _this.formatCondition, modelSchema); }; this.formatAggregation = async function (aggregator, formattedConditions) { const aggregatorOperator = _this.formatAggregatorOperator(aggregator); return { [aggregatorOperator]: formattedConditions }; }; this.formatCondition = async function (condition, isSmartField = false) { const isTextField = _this.isTextField(condition.field); if (isSmartField) { return _this.formatOperatorValue(condition.operator, condition.value, isTextField); } const formattedField = _this.formatField(condition.field); if (_this.operatorDateParser.isDateOperator(condition.operator)) { return { [formattedField]: _this.operatorDateParser.getDateFilter(condition.operator, condition.value) }; } return { [formattedField]: _this.formatOperatorValue(condition.operator, condition.value, isTextField) }; }; this.formatAggregatorOperator = function (aggregatorOperator) { switch (aggregatorOperator) { case 'and': return _this.OPERATORS.AND; case 'or': return _this.OPERATORS.OR; default: throw new _errors.NoMatchingOperatorError(); } }; this.formatOperatorValue = function (operator, value, isTextField = false) { switch (operator) { case 'not': return { [_this.OPERATORS.NOT]: value }; case 'greater_than': case 'after': return { [_this.OPERATORS.GT]: value }; case 'less_than': case 'before': return { [_this.OPERATORS.LT]: value }; case 'contains': return { [_this.OPERATORS.LIKE]: `%${value}%` }; case 'starts_with': return { [_this.OPERATORS.LIKE]: `${value}%` }; case 'ends_with': return { [_this.OPERATORS.LIKE]: `%${value}` }; case 'not_contains': return { [_this.OPERATORS.NOT_LIKE]: `%${value}%` }; case 'present': return { [_this.OPERATORS.NE]: null }; case 'not_equal': return { [_this.OPERATORS.NE]: value }; case 'blank': return isTextField ? { [_this.OPERATORS.OR]: [{ [_this.OPERATORS.EQ]: null }, { [_this.OPERATORS.EQ]: '' }] } : { [_this.OPERATORS.EQ]: null }; case 'equal': return { [_this.OPERATORS.EQ]: value }; case 'includes_all': return { [_this.OPERATORS.CONTAINS]: value }; case 'in': return typeof value === 'string' ? { [_this.OPERATORS.IN]: value.split(',').map(function (elem) { return elem.trim(); }) } : { [_this.OPERATORS.IN]: value }; default: throw new _errors.NoMatchingOperatorError(); } }; this.formatField = function (field) { if (field.includes(':')) { const [associationName, fieldName] = field.split(':'); return `$${getReferenceField(_forestExpress.Schemas.schemas, modelSchema, associationName, fieldName)}$`; } return field; }; this.isTextField = function (field) { if (field.includes(':')) { const [associationName, fieldName] = field.split(':'); const associationSchema = getReferenceSchema(_forestExpress.Schemas.schemas, modelSchema, associationName, fieldName); if (associationSchema) { return _forestExpress.SchemaUtils.getFieldType(associationSchema, field) === 'String'; } return false; } return _forestExpress.SchemaUtils.getFieldType(modelSchema, field) === 'String'; }; // NOTICE: Look for a previous interval condition matching the following: // - If the filter is a simple condition at the root the check is done right away. // - There can't be a previous interval condition if the aggregator is 'or' (no meaning). // - The condition's operator has to be elligible for a previous interval. // - There can't be two previous interval condition. this.getPreviousIntervalCondition = function (filtersString) { const filters = _forestExpress.BaseFiltersParser.parseFiltersString(filtersString); let currentPreviousInterval = null; // NOTICE: Leaf condition at root if (filters && !filters.aggregator) { if (_this.operatorDateParser.hasPreviousDateInterval(filters.operator)) { return filters; } return null; } // NOTICE: No previous interval condition when 'or' aggregator if (filters.aggregator === 'and') { for (let i = 0; i < filters.conditions.length; i += 1) { const condition = filters.conditions[i]; // NOTICE: Nested filters if (condition.aggregator) { return null; } if (_this.operatorDateParser.hasPreviousDateInterval(condition.operator)) { // NOTICE: There can't be two previousInterval. if (currentPreviousInterval) { return null; } currentPreviousInterval = condition; } } } return currentPreviousInterval; }; this.getAssociations = async function (filtersString) { return _forestExpress.BaseFiltersParser.getAssociations(filtersString); }; } module.exports = FiltersParser;