Bläddra i källkod

Merge pull request #38 from RiveraGroup/feature/mongo_2.6.5_expressions_CoerceToBool

Feature/mongo 2.6.5 expressions coerce to bool
Kyle P Davis 11 år sedan
förälder
incheckning
7d7338c8cc

+ 20 - 24
lib/pipeline/expressions/CoerceToBoolExpression.js

@@ -6,27 +6,32 @@
  * @namespace mungedb-aggregate.pipeline.expressions
  * @module mungedb-aggregate
  * @constructor
- **/
-var CoerceToBoolExpression = module.exports = function CoerceToBoolExpression(expression){
-	if (arguments.length !== 1) throw new Error("args expected: expression");
-	this.expression = expression;
+ */
+var CoerceToBoolExpression = module.exports = function CoerceToBoolExpression(theExpression){
+	if (arguments.length !== 1) throw new Error(klass.name + ": expected args: expr");
+	this.expression = theExpression;
 	base.call(this);
 }, klass = CoerceToBoolExpression, base = require("./Expression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
-// DEPENDENCIES
 var Value = require("../Value"),
 	AndExpression = require("./AndExpression"),
 	OrExpression = require("./OrExpression"),
 	NotExpression = require("./NotExpression"),
 	Expression = require("./Expression");
 
+klass.create = function create(expression) {
+	var newExpr = new CoerceToBoolExpression(expression);
+	return newExpr;
+};
+
 proto.optimize = function optimize() {
-	this.expression = this.expression.optimize();   // optimize the operand
+	// optimize the operand
+	this.expression = this.expression.optimize();
 
 	// if the operand already produces a boolean, then we don't need this
 	// LATER - Expression to support a "typeof" query?
 	var expr = this.expression;
-	if(expr instanceof AndExpression ||
+	if (expr instanceof AndExpression ||
 			expr instanceof OrExpression ||
 			expr instanceof NotExpression ||
 			expr instanceof CoerceToBoolExpression)
@@ -35,28 +40,19 @@ proto.optimize = function optimize() {
 };
 
 proto.addDependencies = function addDependencies(deps, path) {
-	return this.expression.addDependencies(deps);
+	this.expression.addDependencies(deps);
 };
 
-// PROTOTYPE MEMBERS
-proto.evaluateInternal = function evaluateInternal(vars){
+proto.evaluateInternal = function evaluateInternal(vars) {
 	var result = this.expression.evaluateInternal(vars);
 	return Value.coerceToBool(result);
 };
 
 proto.serialize = function serialize(explain) {
-	if ( explain ) {
-		return {$coerceToBool:[this.expression.toJSON()]};
-	}
-	else {
-		return {$and:[this.expression.toJSON()]};
-	}
+	// When not explaining, serialize to an $and expression. When parsed, the $and expression
+	// will be optimized back into a ExpressionCoerceToBool.
+	var name = explain ? "$coerceToBool" : "$and",
+		obj = {};
+	obj[name] = [this.expression.serialize(explain)];
+	return obj;
 };
-
-proto.toJSON = function toJSON() {
-	// Serializing as an $and expression which will become a CoerceToBool
-	return {$and:[this.expression.toJSON()]};
-};
-
-//TODO: proto.addToBsonObj   --- may be required for $project to work
-//TODO: proto.addToBsonArray

+ 56 - 34
test/lib/pipeline/expressions/CoerceToBoolExpression.js

@@ -1,59 +1,81 @@
 "use strict";
 var assert = require("assert"),
 	CoerceToBoolExpression = require("../../../../lib/pipeline/expressions/CoerceToBoolExpression"),
+	Expression = require("../../../../lib/pipeline/expressions/Expression"),
 	FieldPathExpression = require("../../../../lib/pipeline/expressions/FieldPathExpression"),
-	ConstantExpression = require("../../../../lib/pipeline/expressions/ConstantExpression");
+	ConstantExpression = require("../../../../lib/pipeline/expressions/ConstantExpression"),
+	DepsTracker = require("../../../../lib/pipeline/DepsTracker");
 
+exports.CoerceToBoolExpression = {
 
-module.exports = {
+	"constructor()": {
 
-	"CoerceToBoolExpression": {
-
-		"constructor()": {
-
-			"should throw Error if no args": function construct(){
-				assert.throws(function(){
-					new CoerceToBoolExpression();
-				});
-			}
+		"should create instance": function() {
+			var nested = ConstantExpression.create(5);
+			assert(new CoerceToBoolExpression(nested) instanceof Expression);
+		},
 
+		"should throw Error unless one arg": function() {
+			assert.throws(function() {
+				new CoerceToBoolExpression();
+			});
+			assert.throws(function() {
+				new CoerceToBoolExpression("foo", "bar");
+			});
 		},
 
-		"#evaluate()": {
+	},
 
-			"should return true if nested expression is coerced to true; {$const:5}": function testEvaluateTrue(){
-				var expr = new CoerceToBoolExpression(new ConstantExpression(5));
-				assert.equal(expr.evaluateInternal({}), true);
-			},
+	"#evaluate()": {
 
-			"should return false if nested expression is coerced to false; {$const:0}": function testEvaluateFalse(){
-				var expr = new CoerceToBoolExpression(new ConstantExpression(0));
-				assert.equal(expr.evaluateInternal({}), false);
-			}
+		"should return true if nested expression is coerced to true; {$const:5}": function testEvaluateTrue() {
+			/** Nested expression coerced to true. */
+			var nested = ConstantExpression.create(5),
+				expr = CoerceToBoolExpression.create(nested);
+			assert.strictEqual(expr.evaluate({}), true);
+		},
 
+		"should return false if nested expression is coerced to false; {$const:0}": function testEvaluateFalse() {
+			/** Nested expression coerced to false. */
+			var expr = CoerceToBoolExpression.create(ConstantExpression.create(0));
+			assert.strictEqual(expr.evaluate({}), false);
 		},
 
-		"#addDependencies()": {
+	},
 
-			"should forward dependencies of nested expression": function testDependencies(){
-				var expr = new CoerceToBoolExpression(new FieldPathExpression('a.b')),
-					deps = expr.addDependencies({});
-				assert.equal(Object.keys(deps).length, 1);
-				assert.ok(deps['a.b']);
-			}
+	"#addDependencies()": {
 
+		"should forward dependencies of nested expression": function testDependencies() {
+			/** Dependencies forwarded from nested expression. */
+			var nested = FieldPathExpression.create("a.b"),
+				expr = CoerceToBoolExpression.create(nested),
+				deps = new DepsTracker();
+			expr.addDependencies(deps);
+			assert.strictEqual( Object.keys(deps.fields).length, 1 );
+			assert.strictEqual("a.b" in deps.fields, true);
+			assert.strictEqual(deps.needWholeDocument, false);
+			assert.strictEqual(deps.needTextScore, false);
 		},
 
-		"#toJSON()": {
+	},
 
-			"should serialize as $and which will coerceToBool; '$foo'": function(){
-				var expr = new CoerceToBoolExpression(new FieldPathExpression('foo'));
-				assert.deepEqual(expr.toJSON(), {$and:['$foo']});
-			}
+	"#serialize": {
 
-		}
+		"should be able to output in to JSON Object": function testAddToBsonObj() {
+			/** Output to BSONObj. */
+			var expr = CoerceToBoolExpression.create(FieldPathExpression.create("foo"));
+            // serialized as $and because CoerceToBool isn't an ExpressionNary
+			assert.deepEqual({field:{$and:["$foo"]}}, {field:expr.serialize(false)});
+		},
+
+		"should be able to output in to JSON Array": function testAddToBsonArray() {
+			/** Output to BSONArray. */
+			var expr = CoerceToBoolExpression.create(FieldPathExpression.create("foo"));
+			// serialized as $and because CoerceToBool isn't an ExpressionNary
+			assert.deepEqual([{$and:["$foo"]}], [expr.serialize(false)]);
+		},
 
-	}
+	},
 
 };