define([
'bop/js/EmptyCondition',
'bop/js/api/operation/CompositeCondition',
'core/js/api/utils/StringUtils',
'entity/js/api/PropertyType',
'operation/js/api/Condition',
'operation/js/api/FieldPath',
'operation/js/api/Operator',
'operation/js/query/QueryType'
], function(
EmptyCondition,
CompositeCondition,
StringUtils,
PropertyType,
Condition,
FieldPath,
Operator,
QueryType) {
'use strict';
/**
* Represents a single filtering rule which can be applied by the client to fetch only records matching the given restriction.
*
* <p>
* {@link bop/js/api/operation/SimpleCondition SimpleCondition} is not expected to be created directly by the client. It's only consumed by the {@link bop/js/spi/operation/ConditionVisitor#visitSimpleCondition ConditionVisitor.visitSimpleCondition(..)}
* method where {@link bop/js/spi/BOP BOP} author is expected to interpret incoming {@link operation/js/api/Condition Condition}s and transform them into proper URL query or generally process them any way (s)he need.
* </p>
*
* @AbcsExtension stable
* @version 17.1.1
* @exports bop/js/api/operation/SimpleCondition
*
* @constructor
* @private
*
* @see {@link entity/js/api/Property Property}
* @see {@link module:operation/js/api/Operator Operator}
* @see {@link bop/js/api/operation/CompositeCondition CompositeCondition}
* @see {@link module:operation/js/api/Conditions.SIMPLE Conditions.SIMPLE(..)} to create instances of {@link bop/js/api/operation/SimpleCondition SimpleCondition}
* @see {@link bop/js/spi/operation/ConditionVisitor#visitSimpleCondition ConditionVisitor.visitSimpleCondition(..)} to process instances of {@link bop/js/api/operation/SimpleCondition SimpleCondition}
*
* @param {QueryParameterDescription} queryParameterDescription
* @param {Operator} operator
* @param {String} value
* @param {SimpleCondition.Expression} valueExpression - expression which needs to be evaluated to get real live 'value'.
* You may instantiate an expression with SimpleCondition.createExpression().
* @param {QueryType} type
* @param {String} valuePlaceholder
* @param {boolean} userSpecified
*/
var SimpleCondition = function(queryParameterDescription, operator, value, valueExpression, type, valuePlaceholder, userSpecified) {
AbcsLib.checkThis(this);
Condition.apply(this, arguments);
var self = this;
self._value = value;
self.setValueExpression(valueExpression);
self._operator = operator;
self._type = type;
self._valuePlaceholder = valuePlaceholder;
self._lookupReplaced = false;
self._queryParamDescription = queryParameterDescription;
self._userSpecified = userSpecified;
self._fieldPath = queryParameterDescription
? FieldPath.fromDescription(queryParameterDescription.getFieldPathDescription())
: undefined;
};
AbcsLib.extend(SimpleCondition, Condition);
SimpleCondition._LOGGER = Logger.get('SimpleCondition');
SimpleCondition._UNKNOWN_OPERATOR = 'SimpleCondition.match() called with Operator that doesn\'t seem to be implemented yet. \n\
Please file an issue with steps which you\'ve proceed, so it gets fixed correctly';
/**
* Checks whether the given recordData matches condition described by this {@link SimpleCondition}.
*
* @param {Map<String, String>} recordData - Map[key = PropertyID, value = Record value]
* @returns {boolean}
*/
SimpleCondition.prototype.match = function(recordData) {
var self = this;
var propertyID = self.getPropertyID();
var propertyType = self.getProperty().getType();
var value = recordData[propertyID];
if (typeof value === 'object' && value !== null) {
value = value.id;
}
var isEmpty = value === null || value === undefined || StringUtils.isEmpty(value);
switch (self._operator) {
case Operator.IS_EMPTY:
return isEmpty;
case Operator.IS_NOT_EMPTY:
return !isEmpty;
case Operator.EQUALS:
// Special handling for cases where both values are null/undefined/empty
var isThisEmpty = this._value === null || this._value === undefined || StringUtils.isEmpty(this._value);
if (isThisEmpty && isEmpty) {
return true;
}
break;
default:
break;
}
switch (propertyType) {
case PropertyType.DATE:
case PropertyType.TIME:
case PropertyType.DATETIME:
return self._matchDates(value);
case PropertyType.NUMBER:
case PropertyType.CURRENCY:
case PropertyType.PERCENTAGE:
return self._matchNumbers(value);
default:
return self._matchStrings(value);
}
};
SimpleCondition.prototype._matchDates = function(value) {
var self = this;
switch (self._operator) {
case Operator.LESS:
return value < this._value;
case Operator.LESS_OR_EQUAL:
return value <= this._value;
case Operator.MORE:
return value > this._value;
case Operator.MORE_OR_EQUAL:
return value >= this._value;
default:
SimpleCondition._LOGGER.error(SimpleCondition._UNKNOWN_OPERATOR);
return true;
}
};
SimpleCondition.prototype._matchNumbers = function(value) {
var self = this;
switch (self._operator) {
case Operator.EQUALS:
return value === this._value;
case Operator.NOT_EQUALS:
return value !== this._value;
case Operator.LESS:
return value < this._value;
case Operator.LESS_OR_EQUAL:
return value <= this._value;
case Operator.MORE:
return value > this._value;
case Operator.MORE_OR_EQUAL:
return value >= this._value;
default:
SimpleCondition._LOGGER.error(SimpleCondition._UNKNOWN_OPERATOR);
return true;
}
};
SimpleCondition.prototype._matchStrings = function(value) {
var self = this;
switch (self._operator) {
case Operator.EQUALS:
return StringUtils.equalsIgnoreCase(value, this._value);
case Operator.NOT_EQUALS:
return !StringUtils.equalsIgnoreCase(value, this._value);
case Operator.STARTS_WITH:
return StringUtils.startsWithIgnoreCase(value, this._value);
case Operator.ENDS_WITH:
return StringUtils.endsWithIgnoreCase(value, this._value);
case Operator.CONTAINS:
return StringUtils.containsIgnoreCase(value, this._value);
default:
SimpleCondition._LOGGER.error(SimpleCondition._UNKNOWN_OPERATOR);
return true;
}
};
/**
* Gets the {@link module:operation/js/api/Operator Operator} assigned to this {@link bop/js/api/operation/SimpleCondition SimpleCondition}.
*
* @AbcsExtension stable
* @version 17.1.1
*
* @returns {module:operation/js/api/Operator}
*/
SimpleCondition.prototype.getOperator = function() {
return this._operator;
};
SimpleCondition.prototype.hasValueExpression = function() {
if (this._valueExpression && this._valueExpression.getValue()) {
return true;
}
return false;
};
SimpleCondition.prototype.setValueExpression = function(valueExpression) {
if (valueExpression) {
valueExpression = SimpleCondition.createExpression(valueExpression);
}
this._valueExpression = valueExpression;
};
SimpleCondition.prototype.getValueExpression = function() {
return this._valueExpression;
};
SimpleCondition.prototype.getValuePlaceholder = function() {
return this._valuePlaceholder;
};
SimpleCondition.prototype.setValue = function(value) {
this._value = value;
};
/**
* Gets the value assigned to this {@link bop/js/api/operation/SimpleCondition SimpleCondition}.
*
* @AbcsExtension stable
* @version 17.1.1
*
* @returns {String}
*/
SimpleCondition.prototype.getValue = function() {
return this._value;
};
SimpleCondition.prototype.setUserSpecified = function (userSpecified) {
this._userSpecified = userSpecified;
};
SimpleCondition.prototype.isUserSpecified = function () {
return this._userSpecified;
};
SimpleCondition.prototype.getType = function() {
return this._type;
};
SimpleCondition.prototype.isLookupReplaced = function() {
return this._lookupReplaced;
};
SimpleCondition.prototype.setLookupReplaced = function() {
this._lookupReplaced = true;
};
/**
* Gets the {@link entity/js/api/Property Property} assigned to this {@link bop/js/api/operation/SimpleCondition SimpleCondition}.
*
* @AbcsExtension stable
* @version 17.1.1
*
* @returns {entity/js/api/Property}
*/
SimpleCondition.prototype.getProperty = function() {
return this._queryParamDescription.getProperty();
};
SimpleCondition.prototype.getFieldPath = function() {
return this._fieldPath;
};
/**
* Gets the custom information defined for the parameter descriptor assigned to this {@link bop/js/api/operation/SimpleCondition SimpleCondition}.
*
* @AbcsExtension stable
* @version 17.1.1
*
* @returns {Object}
*
* @see {@link bop/js/api/operation/OperationInput#parameter OperationInput.parameter(..)} to understand where is additional info defined.
*/
SimpleCondition.prototype.getAdditionalInfo = function() {
return this._queryParamDescription.getAdditionalInfo();
};
SimpleCondition.prototype.getParameterType = function() {
return this._queryParamDescription.getParameterType();
};
SimpleCondition.prototype.getPropertyID = function() {
return this.getProperty().getId();
};
/**
* Checks wheather this query parameter is required or not.
* @returns {boolean}
*/
SimpleCondition.prototype.isRequired = function() {
return this._queryParamDescription.isRequired();
};
SimpleCondition.prototype.clone = function() {
return new SimpleCondition(
this._queryParamDescription,
this._operator,
this._value,
this._valueExpression,
this._type,
this._valuePlaceholder,
this._userSpecified,
this._fieldPath
);
};
SimpleCondition.prototype.getDefinition = function() {
var res = {
//name: this.getProperty().getId(),
fieldPath: this._fieldPath && this._fieldPath.toJSON(),
operator: this.getOperator(),
value: this.getValue(),
valueExpression: this._valueExpression && this._valueExpression.getDefinition(),
valuePlaceholder: this.getValuePlaceholder(),
type: this.getType()
};
var userSpec = this.isUserSpecified();
if (AbcsLib.isDefined(userSpec)) {
res.userSpecified = userSpec;
}
return res;
};
SimpleCondition.createFromDefinition = function(queryParamJSON, queryDescription) {
var name;
if (queryParamJSON.fieldPath) {
var fp = FieldPath.createFromDefinition(queryParamJSON.fieldPath);
name = fp.getId();
} else if (queryParamJSON.name) {
// Backward compatibility
name = queryParamJSON.name;
}
var paramDesc = name ? queryDescription.getQueryParameter(name) : undefined;
if (paramDesc) {
return new SimpleCondition(
paramDesc,
queryParamJSON.operator,
queryParamJSON.value,
queryParamJSON.valueExpression && SimpleCondition.createExpression(queryParamJSON.valueExpression),
QueryType.forValue(queryParamJSON.type),
queryParamJSON.valuePlaceholder,
queryParamJSON.userSpecified);
}
};
SimpleCondition.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;
}
return new CompositeCondition(relationOperator, [this, condition]);
};
SimpleCondition.prototype.visit = function(conditionVisitor) {
return conditionVisitor.visitSimpleCondition(this);
};
SimpleCondition.prototype.getSubConditions = function() {
return [];
};
SimpleCondition.Expression = function (value, displayName) {
AbcsLib.checkThis(this);
this._value = value;
this._displayName = displayName || value;
};
SimpleCondition.Expression.prototype.getValue = function () {
return this._value || '';
};
SimpleCondition.Expression.prototype.getDisplayName = function () {
return this._displayName || '';
};
SimpleCondition.Expression.prototype.getDefinition = function () {
return {
value: this.getValue(),
displayName: this.getDisplayName()
};
};
SimpleCondition.createExpression = function (value, displayName) {
if (value && typeof value === 'object') {
displayName = value.displayName || value._displayName;
value = value.value || value._value;
}
return new SimpleCondition.Expression(value, displayName);
};
return SimpleCondition;
});