ソースを参照

Merge branch 'bugfix/mongo_2.6.5_expressions_Let' into feature/mongo_2.6.5_expressions_Let

Conflicts:
	test/lib/pipeline/expressions/LetExpression_test.js
Tony Ennis 11 年 前
コミット
89f637274d

+ 19 - 12
lib/pipeline/expressions/LetExpression.js

@@ -1,29 +1,29 @@
 "use strict";
 
 var LetExpression = module.exports = function LetExpression(vars, subExpression){
-	//if (arguments.length !== 2) throw new Error("Two args expected");
+	if (arguments.length !== 2) throw new Error("Two args expected");
 	this._variables = vars;
 	this._subExpression = subExpression;
 }, klass = LetExpression, Expression = require("./Expression"), base = Expression, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
-Expression.registerExpression("$let", LetExpression.parse);
-
 // DEPENDENCIES
 var Variables = require("./Variables"),
 	VariablesParseState = require("./VariablesParseState");
 
 // PROTOTYPE MEMBERS
 
-proto.parse = function parse(expr, vpsIn){
-	if(!("$let" in expr)) {
-		throw new Error("Tried to create a $let with something other than let. Looks like your parse map went all funny.");
-	}
+klass.parse = function parse(expr, vpsIn){
+	//NOTE: DEVIATION FROM MONGO: I don't believe this works for us since the operator has been removed from expr by the time
+	// we get here.
+//	if(!("$let" in expr)) {
+//		throw new Error("Tried to create a $let with something other than let. Looks like your parse map went all funny.");
+//	}
 
-	if(typeof(expr.$let) !== 'object' || (expr.$let instanceof Array)) {
+	if(typeof(expr) !== 'object' || (expr instanceof Array)) {
 		throw new Error("$let only supports an object as its argument: 16874");
 	}
 
-	var args = expr.$let,
+	var args = expr,
 		varsElem = args.vars,
 		inElem = args['in']; // args.in; ??
 
@@ -50,16 +50,23 @@ proto.parse = function parse(expr, vpsIn){
 		throw new Error("Unrecognized parameter to $let: " + bogus.join(",") + "- 16875");
 	}
 
-	var vpsSub = new VariablesParseState(vpsIn),
+	var vpsSub = vpsIn, //new VariablesParseState(vpsIn),
 		vars = {};
 
-	for(var varName in varsElem) {
+	varsElem.forEach(function(varName){
 		Variables.uassertValidNameForUserWrite(varName);
 		var id = vpsSub.defineVariable(varName);
 
 		vars[id] = {};
 		vars[id][varName] = Expression.parseOperand(varsElem, vpsIn);
-	}
+	});
+//	for(var varName in varsElem) {
+//		Variables.uassertValidNameForUserWrite(varsElem[varName);
+//		var id = vpsSub.defineVariable(varName);
+//
+//		vars[id] = {};
+//		vars[id][varName] = Expression.parseOperand(varsElem, vpsIn);
+//	}
 
 	var subExpression = Expression.parseOperand(inElem, vpsSub);
 	return new LetExpression(vars, subExpression);

+ 92 - 73
test/lib/pipeline/expressions/LetExpression_test.js

@@ -1,100 +1,119 @@
 "use strict";
 var assert = require("assert"),
-	LetExpression = require("../../../../lib/pipeline/expressions/LetExpression");
-	//Expression = require("../../../../lib/pipeline/expressions/Expression");
+
+	LetExpression = require("../../../../lib/pipeline/expressions/LetExpression"),
+	ConstantExpression = require("../../../../lib/pipeline/expressions/ConstantExpression"),
+	FieldPathExpression = require("../../../../lib/pipeline/expressions/FieldPathExpression"),
+	VariablesParseState = require("../../../../lib/pipeline/expressions/VariablesParseState"),
+	VariablesIdGenerator = require("../../../../lib/pipeline/expressions/VariablesIdGenerator"),
+	Expression = require("../../../../lib/pipeline/expressions/Expression");
 
 
 module.exports = {
 
 	"LetExpression": {
 
+		beforeEach: function() {
+			this.vps = new VariablesParseState(new VariablesIdGenerator());
+		},
+
 		"constructor()": {
 
-			"should throw when there are not 2 args": function testConstructorNot2() {
+
+			"should throw an Error when constructing without args": function () {
 				assert.throws(function () {
-					new LetExpression({});
+					new LetExpression();
 				});
+			},
+			"should throw Error when constructing with one arg": function () {
 				assert.throws(function () {
-					new LetExpression({}, {}, {});
+					new LetExpression(1);
 				});
 			},
-			"should not throw when there are 2 args": function testConstructor2() {
+			"should not throw when constructing with two args": function () {
 				assert.doesNotThrow(function () {
-					new LetExpression({}, {});
-				});
-			}
-		},
-
-		"#parse()": {
-			"should throw if $let isn't in expr": function () {
-				assert.throws(function(){
-					new LetExpression().parse({$noLetIsHere:1}, {})
-				});
-			},
-			"should throw if the $let expression isn't an object": function () {
-				assert.throws(function(){
-					new LetExpression().parse({$expr:"this is not an object"}, {})
-				});
-			},
-			"should throw if the $let expression is an array": function () {
-				assert.throws(function(){
-					new LetExpression().parse({$expr:[1,2,3]}, {})
-				});
-			},
-			"should throw if there is no vars parameter to $let": function () {
-				assert.throws(function(){
-					new LetExpression().parse({$expr:{noVars:1}}, {})
+					new LetExpression(1, 2);
 				});
 			},
-			"should throw if there is no input parameter to $let": function () {
-				assert.throws(function(){
-					new LetExpression().parse({$expr:{vars:1, noIn:2}}, {})
-				});
-			},
-			"should throw if any of the arguments to $let are not 'in' or 'var'": function () {
-				assert.throws(function(){
-					new LetExpression().parse({$expr:{vars:1, in:2, zoot:3}}, {})
-				});
-			},
-			"should throw if the var name is not writable": function () {
-				assert.throws(function(){
-					new LetExpression().parse({$expr:{vars:["$$bad$$"], in:2}}, {})
-				});
+
+			"#parse()": {
+				beforeEach: function(){
+					var self = this;
+					this.dieForTheRightReason = function(expr, regex) {
+						var self = this;
+						assert.throws(function () {
+							Expression.parseOperand(expr, self.vps);
+						}, regex);
+					}
+				},
+				"should throw if $let isn't in expr": function () {
+					this.dieForTheRightReason({$xlet: ['$$a', 1]}, /15999/);
+				},
+				"should throw if the $let expression isn't an object": function () {
+					this.dieForTheRightReason({$let: "this is not an object"}, /16874/);
+				},
+				"should throw if the $let expression is an array": function () {
+					this.dieForTheRightReason({$let: [1, 2, 3]}, /16874/);
+				},
+				"should throw if there is no vars parameter to $let": function () {
+					this.dieForTheRightReason({$let: {noVars: 1}}, /16876/);
+				},
+				"should throw if there is no input parameter to $let": function () {
+					this.dieForTheRightReason({$let: {vars: 1, noIn: 2}}, /16877/);
+				},
+				"should throw if any of the arguments to $let are not 'in' or 'var'": function () {
+					this.dieForTheRightReason({$let: {vars: 1, in: 2, zoot:3}}, /16875/);
+				},
+				"should throw if the var name is not writable": function () {
+					this.dieForTheRightReason({$let: {vars: ["$$bad$$"], in: 2}}, /16867/);
+				},
+				"should return a Let expression": function () {
+					var x = Expression.parseOperand({$let: {vars: ["a"], in: 2}}, this.vps);
+					assert(x instanceof LetExpression);
+					assert(x._subExpression instanceof ConstantExpression);
+					assert(x._subExpression.getValue() == 2);
+					assert(x._variables[0].a instanceof ConstantExpression);
+					assert(x._variables[0].a.getValue()[0] === 'a');
+				},
+				"should show we collect multiple vars": function() {
+					var x = Expression.parseOperand({$let: {vars: ["a", "b", "c"], in: 2}}, this.vps);
+					assert.deepEqual(x._variables[0].a.getValue(), ['a','b','c']);
+					assert.deepEqual(x._variables[1].b.getValue(), ['a','b','c']);
+					assert.deepEqual(x._variables[2].c.getValue(), ['a','b','c']);
+				},
+				"should show we require vars to be wrapped in an array.": function () {
+					var self = this;
+					assert.throws(function () {
+						Expression.parseOperand({$let: {vars: "a", in: 2}}, self.vps);
+					}, /TypeError: Object a has no method 'forEach'/);
+				}
 			},
-			"should return a Let expression": function () {
-				var letExpression = new LetExpression().parse({$expr:{vars:["$valid"], in:2}}, {});
-				assert(letExpression);
-				assert(false);	// I don't know how to test this yet.
-			}
-		},
 
-		"#optimize()": {
-			"should optimize subexpressions if there are no variables": function () {
-				assert(fail);
+			"#optimize()": {
+				"should optimize subexpressions if there are no variables": function () {
+					assert(false);
+				},
+				"should optimize variables": function () {
+					assert(false);
+				},
+				"should optimize subexpressions if there are variables": function () {
+					assert(false);
+				}
 			},
-			"should optimize variables": function () {
-				assert(fail);
+			"#serialize()": {
+				"should serialize variables and the subexpression": function () {
+					assert(false);
+				}
 			},
-			"should optimize subexpressions if there are variables": function () {
-				assert(fail);
-			}
-		},
-		"#serialize()": {
-			"should serialize variables and the subexpression": function () {
-				assert(fail);
-			}
-		},
-		"#evaluateInternal()": {
-			"should preform the evaluation for variables and the subexpression": function () {
-				assert(fail);
-			}
-		},
-		"#addDependencies()": {
-			"add dependencies to the variables and the subexpression": function () {
-				assert(fail);
+			"#evaluateInternal()": {
+				"should preform the evaluation for variables and the subexpression": function () {
+					assert(false);
+				}
 			}
 		}
 	}
 };
 
-if (!module.parent)(new (require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);
+
+if (!module.parent)(new (require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);
+