coveo-search-ui
Version:
Coveo JavaScript Search Framework
140 lines (123 loc) • 4.49 kB
text/typescript
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;
}
}