UNPKG

coveo-search-ui

Version:

Coveo JavaScript Search Framework

140 lines (123 loc) 4.49 kB
import { Assert } from '../../misc/Assert'; import { QueryUtils } from '../../utils/QueryUtils'; import * as _ from 'underscore'; /** * An `ExpressionBuilder` that is mostly used by the {@link QueryBuilder}.<br/> * It is used to build a single query expression.<br/> * It allows combining multiple expression parts into a single string and provides utilities to generate common expression parts. */ export class ExpressionBuilder { private parts: string[] = []; // he he he public wrapParts: boolean = true; /** * Add a new part to the expression. * @param expression */ public add(expression: string) { Assert.isNonEmptyString(expression); this.parts.push(expression); } /** * Take another `ExpressionBuilder`, and copy it. * @param expression */ public fromExpressionBuilder(expression: ExpressionBuilder) { this.parts = this.parts.concat(expression.parts); } /** * Add a new part to the expression, but specific for field values<br/> * eg @field=(value1,value2,value3). * @param field The field for which to create an expression (e.g.: @foo). * @param operator The operator to use e.g.: = (equal) == (strict equal) <> (not equal). * @param values The values to put in the expression. * @param forceValueEscape Force the escaping of the values */ public addFieldExpression(field: string, operator: string, values: string[], forceEscape = false) { Assert.isNonEmptyString(field); Assert.stringStartsWith(field, '@'); Assert.isNonEmptyString(operator); Assert.isLargerOrEqualsThan(1, values.length); this.add(QueryUtils.buildFieldExpression(field, operator, values, forceEscape)); } /** * Add a new part to the expression, but specific for field values<br/> * eg : NOT @field==(value1, value2, value3). * @param field The field for which to create an expression (e.g.: @foo) * @param values The values to put in the expression. * @param forceValueEscape Force the escaping of the values */ public addFieldNotEqualExpression(field: string, values: string[], forceEscape = false) { Assert.isNonEmptyString(field); Assert.stringStartsWith(field, '@'); Assert.isLargerOrEqualsThan(1, values.length); this.add(QueryUtils.buildFieldNotEqualExpression(field, values, (forceEscape = false))); } /** * Removes an expression from the builder. * @param expression */ public remove(expression: string) { Assert.isNonEmptyString(expression); var index = _.indexOf(this.parts, expression); if (index != -1) { this.parts.splice(_.indexOf(this.parts, expression), 1); } } /** * Checks if the builder is currently empty. * @returns {boolean} */ public isEmpty(): boolean { return this.parts.length == 0; } /** * Builds the expression string by combining all the parts together.<br/> * @param exp expression to join the different parts, default to a space. * @returns {any} */ public build(exp: string = ' '): string { if (this.parts.length == 0) { return undefined; } else if (this.parts.length == 1) { return this.parts[0]; } else if (this.wrapParts) { return '(' + this.parts.join(')' + exp + '(') + ')'; } else { return this.parts.join(exp); } } /** * @returns array containing the differents parts of the expression */ public getParts(): string[] { return this.parts; } /** * Merges several `ExpressionBuilder` together. * @param builders Builders that should be merged. * @returns {Coveo.ExpressionBuilder} */ static merge(...builders: ExpressionBuilder[]): ExpressionBuilder { var merged = new ExpressionBuilder(); _.each(builders, (builder: ExpressionBuilder) => { merged.parts = merged.parts.concat(builder.parts); }); return merged; } /** * Merges several `ExpressionBuilder` together, using the OR operator. * @param builders Builders that should be merged. * @returns {Coveo.ExpressionBuilder} */ static mergeUsingOr(...builders: ExpressionBuilder[]): ExpressionBuilder { var nonEmpty = _.filter(builders, (b: ExpressionBuilder) => !b.isEmpty()); var merged = new ExpressionBuilder(); if (nonEmpty.length == 1) { merged.parts = [].concat(nonEmpty[0].parts); } else if (nonEmpty.length > 1) { var parts = _.map(nonEmpty, b => b.build()); merged.add('(' + parts.join(') OR (') + ')'); } return merged; } }