Browse Source

EAGLESIX-2651: And: better sync w/ 2.6.5 code

Kyle P Davis 11 years ago
parent
commit
f59d02e79e
1 changed files with 59 additions and 43 deletions
  1. 59 43
      lib/pipeline/expressions/AndExpression.js

+ 59 - 43
lib/pipeline/expressions/AndExpression.js

@@ -7,71 +7,87 @@
  * 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("zero args expected");
+	if (arguments.length !== 0) throw new Error(klass.name + ": no args expected");
 	base.call(this);
-}, klass = AndExpression, base = require("./VariadicExpressionT")(klass), proto = klass.prototype = Object.create(base.prototype, {constructor: {value: klass}});
+}, klass = AndExpression, base = require("./VariadicExpressionT")(AndExpression), proto = klass.prototype = Object.create(base.prototype, {constructor: {value: klass}});
 
-// DEPENDENCIES
 var Value = require("../Value"),
 	ConstantExpression = require("./ConstantExpression"),
 	CoerceToBoolExpression = require("./CoerceToBoolExpression"),
 	Expression = require("./Expression");
 
-// PROTOTYPE MEMBERS
-klass.opName = "$and";
-proto.getOpName = function getOpName() {
-	return klass.opName;
-};
-
-/**
- * Takes an array one or more values and returns true if all of the values in the array are true. Otherwise $and returns false.
- * @method evaluate
- **/
-proto.evaluateInternal = function evaluateInternal(vars) {
-	for (var i = 0, n = this.operands.length; i < n; ++i) {
-		var value = this.operands[i].evaluateInternal(vars);
-		if (!Value.coerceToBool(value)) return false;
-	}
-	return true;
-};
-
-proto.isAssociativeAndCommutative = function isAssociativeAndCommutative() { return true; };
-
 proto.optimize = function optimize() {
-	var expr = base.prototype.optimize.call(this); //optimize the conjunction as much as possible
+	// 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
-	if (!(expr instanceof AndExpression)) return expr;
-	var andExpr = expr;
+	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.
+	/*
+	 * 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) throw new Error("requires operands!");
-	var lastExpr = andExpr.operands[n - 1];
-	if (!(lastExpr instanceof ConstantExpression)) return expr;
+	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(lastExpr.evaluateInternal());
-	if (!last) return new ConstantExpression(false);
+	/*
+	 * 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 new CoerceToBoolExpression(andExpr.operands[0]);
+	/*
+	 * 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.
+	/*
+	 * 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; //truncate the array
 	return expr;
 };
 
-/** Register Expression */
-Expression.registerExpression(klass.opName, base.parse);
+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);
 
-//TODO: proto.toMatcherBson
+proto.getOpName = function getOpName() {
+	return "$and";
+};
+
+proto.isAssociativeAndCommutative = function isAssociativeAndCommutative() {
+	return true;
+};