| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- "use strict";
- /**
- * Create an expression that finds the conjunction of n operands. The
- * conjunction uses short-circuit logic; the expressions are evaluated in the
- * order they were added to the conjunction, and the evaluation stops and
- * returns false on the first operand that evaluates to false.
- *
- * @class AndExpression
- * @extends mungedb-aggregate.pipeline.expressions.VariadicExpressionT
- * @namespace mungedb-aggregate.pipeline.expressions
- * @module mungedb-aggregate
- * @constructor
- */
- var AndExpression = module.exports = function AndExpression() {
- if (arguments.length !== 0) throw new Error(klass.name + ": no args expected");
- base.call(this);
- }, klass = AndExpression, base = require("./VariadicExpressionT")(AndExpression), proto = klass.prototype = Object.create(base.prototype, {constructor: {value: klass}});
- var Value = require("../Value"),
- ConstantExpression = require("./ConstantExpression"),
- CoerceToBoolExpression = require("./CoerceToBoolExpression"),
- Expression = require("./Expression");
- proto.optimize = function optimize() {
- // optimize the conjunction as much as possible
- var expr = base.prototype.optimize.call(this);
- // if the result isn't a conjunction, we can't do anything
- var andExpr = expr instanceof AndExpression ? expr : undefined;
- if (!andExpr)
- return expr;
- /*
- * Check the last argument on the result; if it's not constant (as
- * promised by ExpressionNary::optimize(),) then there's nothing
- * we can do.
- */
- var n = andExpr.operands.length;
- // ExpressionNary::optimize() generates an ExpressionConstant for {$and:[]}.
- if (n <= 0) throw new Error("Assertion failure");
- var lastExpr = andExpr.operands[n - 1],
- constExpr = lastExpr instanceof ConstantExpression ? lastExpr : undefined;
- if (!constExpr)
- return expr;
- /*
- * Evaluate and coerce the last argument to a boolean. If it's false,
- * then we can replace this entire expression.
- */
- var last = Value.coerceToBool(constExpr.getValue());
- if (!last)
- return ConstantExpression.create(false);
- /*
- * If we got here, the final operand was true, so we don't need it
- * anymore. If there was only one other operand, we don't need the
- * conjunction either. Note we still need to keep the promise that
- * the result will be a boolean.
- */
- if (n === 2)
- return CoerceToBoolExpression.create(andExpr.operands[0]);
- /*
- * Remove the final "true" value, and return the new expression.
- *
- * CW TODO:
- * Note that because of any implicit conversions, we may need to
- * apply an implicit boolean conversion.
- */
- andExpr.operands.length = n - 1;
- return expr;
- };
- proto.evaluateInternal = function evaluateInternal(vars) {
- var n = this.operands.length;
- for (var i = 0; i < n; ++i) {
- var value = this.operands[i].evaluateInternal(vars);
- if (!Value.coerceToBool(value))
- return false;
- }
- return true;
- };
- Expression.registerExpression("$and", base.parse);
- proto.getOpName = function getOpName() {
- return "$and";
- };
- proto.isAssociativeAndCommutative = function isAssociativeAndCommutative() {
- return true;
- };
|