Browse Source

Merge pull request #53 from RiveraGroup/feature/mongo_2.6.5_expressions_SetEquals

Feature/mongo 2.6.5 expressions SetEquals
Kyle P Davis 11 years ago
parent
commit
a6cb5b1fe2

+ 33 - 20
lib/pipeline/expressions/SetEqualsExpression.js

@@ -2,37 +2,50 @@
 
 /**
  * A $setequals pipeline expression.
- * @see evaluateInternal
  * @class SetEqualsExpression
  * @namespace mungedb-aggregate.pipeline.expressions
  * @module mungedb-aggregate
  * @constructor
- **/
+ */
 var SetEqualsExpression = module.exports = function SetEqualsExpression() {
+	if (arguments.length !== 0) throw new Error(klass.name + ": no args expected");
 	base.call(this);
-}, klass = SetEqualsExpression, base = require("./NaryBaseExpressionT")(SetEqualsExpression), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
+}, klass = SetEqualsExpression, base = require("./VariadicExpressionT")(SetEqualsExpression), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
-// DEPENDENCIES
 var Value = require("../Value"),
-	Expression = require("./Expression");
+	Expression = require("./Expression"),
+	Helpers = require("./Helpers");
 
-// PROTOTYPE MEMBERS
-proto.getOpName = function getOpName() {
-	return "$setequals";
+proto.validateArguments = function validateArguments(args) {
+	if (args.length < 2)
+		throw new Error(this.getOpName() + " needs at least two arguments had: " +
+			args.length + "; uassert code 17045");
 };
 
-/**
- * Takes 2 arrays. Assigns the second array to the first array.
- * @method evaluateInternal
- **/
 proto.evaluateInternal = function evaluateInternal(vars) {
-	var array1 = this.operands[0].evaluateInternal(vars),
-		array2 = this.operands[1].evaluateInternal(vars);
-	if (array1 instanceof Array) throw new Error(this.getOpName() + ": object 1 must be an array");
-	if (array2 instanceof Array) throw new Error(this.getOpName() + ": object 2 must be an array");
-	array1 = array2;
-	return array1;
+	var n = this.operands.length,
+		lhs;
+
+	for (var i = 0; i < n; i++) {
+		var nextEntry = this.operands[i].evaluateInternal(vars);
+		if (!(nextEntry instanceof Array))
+			throw new Error("All operands of " + this.getOpName() +" must be arrays. One " +
+				"argument is of type: " + Value.getType(nextEntry) + "; uassert code 17044");
+
+		if (i === 0) {
+			lhs = Helpers.arrayToSet(nextEntry);
+		} else {
+			var rhs = Helpers.arrayToSet(nextEntry);
+			if (Object.keys(lhs).join() !== Object.keys(rhs).join()) {
+				return false;
+			}
+		}
+	}
+	return true;
 };
 
-/** Register Expression */
-Expression.registerExpression("$setequals", base.parse);
+Expression.registerExpression("$setEquals", base.parse);
+
+proto.getOpName = function getOpName() {
+	return "$setEquals";
+};

+ 1 - 1
test/lib/pipeline/expressions/SetDifferenceExpression.js

@@ -309,7 +309,7 @@ exports.SetDifferenceExpression = {
 					input: [[1, 2, 4], [1, 2, 2, 4], [4, 1, 2], [2, 1, 1, 4]],
 					expected: {
 						// $setIntersection: [1, 2, 4],
-						// $setEquals: false,
+						// $setEquals: true,
 						// $setUnion: [1, 2, 4],
 					},
 					error: [

+ 319 - 81
test/lib/pipeline/expressions/SetEqualsExpression.js

@@ -1,87 +1,325 @@
 "use strict";
 var assert = require("assert"),
-		SetEqualsExpression = require("../../../../lib/pipeline/expressions/SetEqualsExpression"),
-		Expression = require("../../../../lib/pipeline/expressions/Expression");
-
-
-module.exports = {
-
-		"SetEqualsExpression": {
-
-				"constructor()": {
-
-						"should throw Error when constructing without args": function testConstructor() {
-								assert.throws(function() {
-										new SetEqualsExpression();
-								});
-						}
-
-				},
-
-				"#getOpName()": {
-
-						"should return the correct op name; $setequals": function testOpName() {
-								assert.equal(new SetEqualsExpression([1,2,3],[4,5,6]).getOpName(), "$setequals");
-						}
-
-				},
-
-				"#evaluateInternal()": {
-
-						"Should fail if array1 is not an array": function testArg1() {
-								var array1 = "not an array",
-										array2 = [6, 7, 8, 9];
-								assert.throws(function() {
-										Expression.parseOperand({
-												$setequals: ["$array1", "$array2"]
-										}).evaluateInternal({
-												array1: array1,
-												array2: array2
-										});
-								});
-						},
-
-						"Should fail if array2 is not an array": function testArg2() {
-								var array1 = [1, 2, 3, 4],
-										array2 = "not an array";
-								assert.throws(function() {
-										Expression.parseOperand({
-												$setequals: ["$array1", "$array2"]
-										}).evaluateInternal({
-												array1: array1,
-												array2: array2
-										});
-								});
-						},
-
-						"Should fail if both are not an array": function testArg1andArg2() {
-								var array1 = "not an array",
-										array2 = "not an array";
-								assert.throws(function() {
-										Expression.parseOperand({
-												$setequals: ["$array1", "$array2"]
-										}).evaluateInternal({
-												array1: array1,
-												array2: array2
-										});
-								});
-						},
-
-						"Should pass and array1 should equal array2": function testBasicAssignment() {
-								var array1 = [1, 2, 3, 4],
-										array2 = [6, 7, 8, 9];
-								assert.strictEqual(Expression.parseOperand({
-										$setequals: ["$array1", "$array2"]
-								}).evaluateInternal({
-										array1: array1,
-										array2: array2
-								}), [6, 7, 8, 9]);
-						},
-
-				}
+	SetEqualsExpression = require("../../../../lib/pipeline/expressions/SetEqualsExpression"),
+	ExpectedResultBase = require("./SetExpectedResultBase");
 
+// Mocha one-liner to make these tests self-hosted
+if(!module.parent)return(require.cache[__filename]=null,(new(require("mocha"))({ui:"exports",reporter:"spec",grep:process.env.TEST_GREP})).addFile(__filename).run(process.exit));
+
+exports.SetEqualsExpression = {
+
+	"constructor()": {
+
+		"should not throw Error when constructing without args": function() {
+			assert.doesNotThrow(function() {
+				new SetEqualsExpression();
+			});
+		},
+
+		"should throw Error when constructing with args": function() {
+			assert.throws(function() {
+				new SetEqualsExpression("someArg");
+			});
 		}
 
-};
+	},
+
+	"#getOpName()": {
+
+		"should return the correct op name; $setEquals": function() {
+			assert.equal(new SetEqualsExpression().getOpName(), "$setEquals");
+		}
+
+	},
+
+	"#evaluate()": {
+
+		"should handle when sets are the same": function Same(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2], [1, 2]],
+					expected: {
+						// $setIsSubset: true,
+						$setEquals: true,
+						// $setIntersection: [1, 2],
+						// $setUnion: [1, 2],
+						// $setDifference: [],
+					},
+				},
+			}).run();
+		},
+
+		"should handle when the 2nd set has redundant items": function Redundant(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2], [1, 2, 2]],
+					expected: {
+						// $setIsSubset: true,
+						$setEquals: true,
+						// $setIntersection: [1, 2],
+						// $setUnion: [1, 2],
+						// $setDifference: [],
+					},
+				},
+			}).run();
+		},
+
+		"should handle when the both sets have redundant items": function DoubleRedundant(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 1, 2], [1, 2, 2]],
+					expected: {
+						// $setIsSubset: true,
+						$setEquals: true,
+						// $setIntersection: [1, 2],
+						// $setUnion: [1, 2],
+						// $setDifference: [],
+					},
+				},
+			}).run();
+		},
+
+		"should handle when the 1st set is a superset": function Super(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2], [1]],
+					expected: {
+						// $setIsSubset: false,
+						$setEquals: false,
+						// $setIntersection: [1],
+						// $setUnion: [1, 2],
+						// $setDifference: [2],
+					},
+				},
+			}).run();
+		},
+
+		"should handle when the 2nd set is a superset and has redundant items": function SuperWithRedundant(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2, 2], [1]],
+					expected: {
+						// $setIsSubset: false,
+						$setEquals: false,
+						// $setIntersection: [1],
+						// $setUnion: [1, 2],
+						// $setDifference: [2],
+					},
+				},
+			}).run();
+		},
+
+		"should handle when the 1st set is a subset": function Sub(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1], [1, 2]],
+					expected: {
+						// $setIsSubset: true,
+						$setEquals: false,
+						// $setIntersection: [1],
+						// $setUnion: [1, 2],
+						// $setDifference: [],
+					},
+				},
+			}).run();
+		},
+
+		"should handle when the sets are the same but backwards": function SameBackwards(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2], [2, 1]],
+					expected: {
+						// $setIsSubset: true,
+						$setEquals: true,
+						// $setIntersection: [1, 2],
+						// $setUnion: [1, 2],
+						// $setDifference: [],
+					},
+				},
+			}).run();
+		},
 
-if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);
+		"should handle when the sets do not overlap": function NoOverlap(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2], [8, 4]],
+					expected: {
+						// $setIsSubset: false,
+						$setEquals: false,
+						// $setIntersection: [],
+						// $setUnion: [1, 2, 4, 8],
+						// $setDifference: [1, 2],
+					},
+				},
+			}).run();
+		},
+
+		"should handle when the sets do overlap": function Overlap(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2], [8, 2, 4]],
+					expected: {
+						// $setIsSubset: false,
+						$setEquals: false,
+						// $setIntersection: [2],
+						// $setUnion: [1, 2, 4, 8],
+						// $setDifference: [1],
+					},
+				},
+			}).run();
+		},
+
+		"should handle when the 2nd set is null": function LastNull(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2], null],
+					expected: {
+						// $setIntersection: null,
+						// $setUnion: null,
+						// $setDifference: null,
+					},
+					error: [
+						"$setEquals"
+						// "$setIsSubset"
+					],
+				},
+			}).run();
+		},
+
+		"should handle when the 1st set is null": function FirstNull(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [null, [1, 2]],
+					expected: {
+						// $setIntersection: null,
+						// $setUnion: null,
+						// $setDifference: null,
+					},
+					error: [
+						"$setEquals"
+						// "$setIsSubset"
+					],
+				},
+			}).run();
+		},
+
+		"should handle when the input has no args": function NoArg(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [],
+					expected: {
+						// $setIntersection: [],
+						// $setUnion: [],
+					},
+					error: [
+						"$setEquals"
+						// "$setIsSubset"
+						// "$setDifference"
+					],
+				},
+			}).run();
+		},
+
+		"should handle when the input has one arg": function OneArg(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2]],
+					expected: {
+						// $setIntersection: [1, 2],
+						// $setUnion: [1, 2],
+					},
+					error: [
+						"$setEquals"
+						// "$setIsSubset"
+						// "$setDifference"
+					],
+				},
+			}).run();
+		},
+
+		"should handle when the input has empty arg": function EmptyArg(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2]],
+					expected: {
+						// $setIntersection: [1, 2],
+						// $setUnion: [1, 2],
+					},
+					error: [
+						"$setEquals"
+						// "$setIsSubset"
+						// "$setDifference"
+					],
+				},
+			}).run();
+		},
+
+		"should handle when the input has empty left arg": function LeftArgEmpty(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[]],
+					expected: {
+						// $setIntersection: [],
+						// $setUnion: [],
+					},
+					error: [
+						"$setEquals"
+						// "$setIsSubset"
+						// "$setDifference"
+					],
+				},
+			}).run();
+		},
+
+		"should handle when the input has empty right arg": function RightArgEmpty(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2], []],
+					expected: {
+						// $setIntersection: [],
+						// $setUnion: [1, 2],
+						// $setIsSubset: false,
+						$setEquals: false,
+						// $setDifference: [1, 2],
+					},
+				},
+			}).run();
+		},
+
+		"should handle when the input has many args": function ManyArgs(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[8, 3], ["asdf", "foo"], [80.3, 34], [], [80.3, "foo", 11, "yay"]],
+					expected: {
+						// $setIntersection: [],
+						$setEquals: false,
+						// $setUnion: [3, 8, 11, 34, 80.3, "asdf", "foo", "yay"],
+					},
+					error: [
+						// "$setIsSubset",
+						// "$setDifference",
+					],
+				},
+			}).run();
+		},
+
+		"should handle when the input has many args that are equal sets": function ManyArgsEqual(){
+			new ExpectedResultBase({
+				getSpec: {
+					input: [[1, 2, 4], [1, 2, 2, 4], [4, 1, 2], [2, 1, 1, 4]],
+					expected: {
+						// $setIntersection: [1, 2, 4],
+						$setEquals: true,
+						// $setUnion: [1, 2, 4],
+					},
+					error: [
+						// "$setIsSubset",
+						// "$setDifference",
+					],
+				},
+			}).run();
+		},
+
+	},
+
+};

+ 1 - 1
test/lib/pipeline/expressions/SetIsSubsetExpression.js

@@ -309,7 +309,7 @@ exports.SetIsSubsetExpression = {
 					input: [[1, 2, 4], [1, 2, 2, 4], [4, 1, 2], [2, 1, 1, 4]],
 					expected: {
 						// $setIntersection: [1, 2, 4],
-						// $setEquals: false,
+						// $setEquals: true,
 						// $setUnion: [1, 2, 4],
 					},
 					error: [