UNPKG

elastic-muto

Version:

Easy expressive search queries for Elasticsearch

109 lines (101 loc) 3.15 kB
'use strict'; var debug = require('debug')('elastic-muto'); var isNil = require('lodash.isnil'); var isEmpty = require('lodash.isempty'); var isString = require('lodash.isstring'); var isFunction = require('lodash.isfunction'); var cosmiconfig = require('cosmiconfig'); var mutoParser = require('./muto-parser'); var qryBuilderDef = require('./query-builder-def'); var explorer = cosmiconfig('muto', { packageProp: false, rc: false, js: 'muto.config.js', argv: false, sync: true }); var qryBuilder = Object.assign({}, qryBuilderDef); try { debug('Loading user config using cosmiconfig(sync)'); var result = explorer.load('.'); if (!isNil(result)) { debug('Successfully parsed config -', result); Object.assign(qryBuilder, result.config); } else { debug('muto.config.js not found'); } } catch (err) { console.error('Failed to parse config!'); console.error(err); } /** * Parses given expression and generates an `elastic-builder` query object. * * @example * // Pass expression as string * const qry = muto.parse( * '["discount"] is false or (["psngr_cnt"] > 81 and ["booking_mode"] contains "Airport")' * ) * * // OR * // Pass conditions using helper classes * const qry = muto.parse( * muto.where() * .or(muto.cn('discount').is(false)) * .or( * muto.where() * .and(muto.cn('psngr_cnt', 'gt', 81)) * .and('["booking_mode"] contains "Airport"') * ) * ); * * qry.toJSON() * { * "bool": { * "should": [ * { "term": { "discount": false } }, * { * "bool": { * "must": [ * { * "range": { "psngr_cnt": { "gt": 81 } } * }, * { * "match": { "booking_mode": "Airport" } * } * ] * } * } * ] * } * } * * @param {string|Where|Condition} expr * @param {Array} [notAnalysedFields] * @returns {Object} `elastic-builder` `BoolQuery` object generated by * parsing the expression */ module.exports = function parse(expr, notAnalysedFields) { if (isEmpty(expr)) { throw new Error('Expression cannot be empty!'); } var strExpr = void 0; if (isString(expr)) strExpr = expr;else if (isFunction(expr.build)) strExpr = expr.build();else strExpr = expr.toString(); debug("Parsing expression '%s'", strExpr); /* Wrap expression in (). This handles the edge case of (ConditionA and ConditionB) or (ConditionC and ConditionD) Was not able to handle in PEG.js due to GrammarError: Possible infinite loop when parsing (left recursion: Expression -> Expression). (expr) will be parsed the same as ((expr)) So even if expression is already wrapped, it is okay. */ try { return mutoParser.parse(`(${strExpr})`, Object.assign({ notAnalysedFields: new Set(notAnalysedFields), debug }, qryBuilder)); } catch (err) { console.error('Failed to parse expression', strExpr); err.expression = strExpr; throw err; } };