define([
'bop/js/EmptyCondition',
'bop/js/api/operation/RelationOperator',
'operation/js/api/Condition'
], function (
EmptyCondition,
RelationOperator,
Condition
) {
'use strict';
/**
* Represents a composite filtering rule which can be applied by the client to fetch only records matching the given restrictions.
*
* <p>
* {@link bop/js/api/operation/CompositeCondition CompositeCondition} consist of a single {@link bop/js/api/operation/RelationOperator RelationOperator} and an array of sub-{@link operation/js/api/Condition Condition}s
* which belongs logically under this composition. Assigned {@link bop/js/api/operation/RelationOperator RelationOperator} is always aplied between all passed sub-{@link operation/js/api/Condition Condition}s.
* </p>
*
* <p>
* Sub-{@link operation/js/api/Condition Condition} might be again instance of {@link bop/js/api/operation/CompositeCondition CompositeCondition} which results in a deeper tree based structure or if they are rather
* leafs, they need to be instances of {@link bop/js/api/operation/SimpleCondition SimpleCondition}. That allows Application Builder UI (and also API client when using {@link module:operation/js/api/Conditions Conditions}
* factory) to potentially build any tree structure including parenthesis logic.
* </p>
*
* @AbcsExtension stable
* @version 17.1.1
* @exports bop/js/api/operation/CompositeCondition
*
* @constructor
* @private
*
* @see {@link bop/js/api/operation/SimpleCondition SimpleCondition}
* @see {@link bop/js/api/operation/RelationOperator RelationOperator}
* @see {@link module:operation/js/api/Conditions.OR Conditions.OR(..)} to create {@link bop/js/api/operation/CompositeCondition CompositeCondition}s with {@link bop/js/api/operation/RelationOperator.OR RelationOperator.OR} set.
* @see {@link module:operation/js/api/Conditions.AND Conditions.AND(..)} to create {@link bop/js/api/operation/CompositeCondition CompositeCondition}s with {@link bop/js/api/operation/RelationOperator.OR RelationOperator.AND} set.
* @see {@link bop/js/spi/operation/ConditionVisitor#visitCompositeCondition ConditionVisitor.visitCompositeCondition(..)} to check how {@link bop/js/spi/operation/ConditionVisitor ConditionVisitor} is processed.
*
* @param {bop/js/api/operation/RelationOperator} relationOperator
* @param {Condition[]} conditions
*/
var CompositeCondition = function(relationOperator, conditions) {
AbcsLib.checkThis(this);
Condition.apply(this, conditions);
this._relationOperator = relationOperator;
this._conditions = conditions;
};
AbcsLib.extend(CompositeCondition, Condition);
CompositeCondition._RELATION_OPERATOR = 'relationOperator';
CompositeCondition._CONDITIONS = 'conditions';
CompositeCondition._LOGGER = Logger.get('CompositeCondition');
CompositeCondition.prototype.getDefinition = function() {
var self = this;
var result = {};
result[CompositeCondition._RELATION_OPERATOR] = self._relationOperator;
result[CompositeCondition._CONDITIONS] = [];
for (var i = 0; i < self._conditions.length; i++) {
var condition = self._conditions[i];
result.conditions.push(condition.getDefinition());
}
return result;
};
CompositeCondition.prototype.clone = function() {
var self = this;
var conditions = [];
self._conditions.forEach(function(condition) {
conditions.push(condition.clone());
});
return new CompositeCondition(self._relationOperator, conditions);
};
CompositeCondition.prototype.match = function(recordData) {
var self = this;
var operator = self._relationOperator;
var condition;
switch (operator) {
// If at least one Condition is false, return false immediately
case RelationOperator.AND:
for (var i = 0; i < self._conditions.length; i++) {
condition = self._conditions[i];
if (!condition.match(recordData)) {
return false;
}
}
return true;
// If at least one Condition is true, return true immediately
case RelationOperator.OR:
for (var j = 0; j < self._conditions.length; j++) {
condition = self._conditions[j];
if (condition.match(recordData)) {
return true;
}
}
return false;
default:
CompositeCondition._LOGGER.trace('Unknown operator: ' + operator);
}
};
CompositeCondition.prototype.append = function(condition, relationOperator) {
// If client attempts to append EmptyCondition, simply return this instance
if (condition === null || condition === undefined || condition instanceof EmptyCondition) {
return this;
}
// If relationOperator is defined, create a purely new CompositeCondition which consist from
// the original one and passed value
if (relationOperator) {
return new CompositeCondition(relationOperator, [this, condition]);
}
// No relationOperator means simply appending the given condition into current Composite
this._conditions.push(condition);
return this;
};
CompositeCondition.prototype.visit = function(conditionVisitor) {
return conditionVisitor.visitCompositeCondition(this);
};
/**
* Gets an array of sub-{@link operation/js/api/Condition Condition}s belonging under this {@link bop/js/api/operation/CompositeCondition CompositeCondition}.
*
* <p>
* Sub-{@link operation/js/api/Condition Condition} might be either instance of {@link bop/js/api/operation/CompositeCondition CompositeCondition} which means
* we are dealing with a deeper tree based structure or leafs will be instances of {@link bop/js/api/operation/SimpleCondition SimpleCondition}.
* </p>
*
* @AbcsExtension stable
* @version 17.1.1
*
* @returns {operation/js/api/Condition[]}
*/
CompositeCondition.prototype.getSubConditions = function() {
return this._conditions;
};
/**
* Gets the {@link bop/js/api/operation/RelationOperator RelationOperator} assigned to this {@link bop/js/api/operation/CompositeCondition CompositeCondition}.
*
* @AbcsExtension stable
* @version 17.1.1
*
* @returns {bop/js/api/operation/RelationOperator}
*/
CompositeCondition.prototype.getRelationOperator = function() {
return this._relationOperator;
};
return CompositeCondition;
});