Browse Source

Refs #2069. Added concat expression, since we are using it.

Spencer Rathbun 12 years ago
parent
commit
89ab044f99

+ 49 - 0
lib/pipeline/expressions/ConcatExpression.js

@@ -0,0 +1,49 @@
+"use strict";
+var ConcatExpression = module.exports = (function(){
+	// CONSTRUCTOR
+	/** 
+	 * Creates an expression that concatenates a set of string operands.
+	 *
+	 * @class ConcatExpression
+	 * @namespace mungedb.aggregate.pipeline.expressions
+	 * @module mungedb-aggregate
+	 * @constructor
+	 **/
+	var klass = module.exports = function ConcatExpression(){
+		if(arguments.length !== 0) throw new Error("zero args expected");
+		base.call(this);
+	}, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
+
+	// DEPENDENCIES
+	var Value = require("../Value");
+
+	// PROTOTYPE MEMBERS
+	proto.getOpName = function getOpName(){
+		return "$concat";
+	};
+
+	proto.getFactory = function getFactory(){
+		return klass;	// using the ctor rather than a separate .create() method
+	};
+
+	/**
+	 * Concats a string of values together.
+	 * @method evaluate
+	 **/
+	proto.evaluate = function evaluate(doc) {
+		var result = "";
+		for (var i = 0, n = this.operands.length; i < n; ++i) {
+			var val = this.operands[i].evaluate(doc);
+			if (val === null)
+				return null; // if any operand is null, return null for all
+
+			if (typeof(val) != "string") throw new Error("$concat only supports strings, not " + typeof(val) + "; code 16702");
+
+			result = result + Value.coerceToString(val);
+		}
+
+		return result;
+	};
+
+	return klass;
+})();

+ 1 - 0
lib/pipeline/expressions/Expression.js

@@ -168,6 +168,7 @@ var Expression = module.exports = (function(){
 					new OpDesc("$add", require("./AddExpression"), 0),
 					new OpDesc("$and", require("./AndExpression"), 0),
 					new OpDesc("$cmp", CompareExpression.bind(null, Expression.CmpOp.CMP), OpDesc.FIXED_COUNT, 2),
+					new OpDesc("$concat", require("./ConcatExpression"), 0),
 					new OpDesc("$cond", require("./CondExpression"), OpDesc.FIXED_COUNT, 3),
 			//		$const handled specially in parseExpression
 					new OpDesc("$dayOfMonth", require("./DayOfMonthExpression"), OpDesc.FIXED_COUNT, 1),

+ 61 - 0
test/lib/pipeline/expressions/ConcatExpression.js

@@ -0,0 +1,61 @@
+"use strict";
+var assert = require("assert"),
+	ConcatExpression = require("../../../../lib/pipeline/expressions/ConcatExpression"),
+	Expression = require("../../../../lib/pipeline/expressions/Expression");
+
+
+module.exports = {
+
+	"ConcatExpression": {
+
+		"constructor()": {
+
+			"should not throw Error when constructing without args": function testConstructor(){
+				assert.doesNotThrow(function(){
+					new ConcatExpression();
+				});
+			}
+
+		},
+
+		"#getOpName()": {
+
+			"should return the correct op name; $concat": function testOpName(){
+				assert.equal(new ConcatExpression().getOpName(), "$concat");
+			}
+
+		},
+
+		"#getFactory()": {
+
+			"should return the constructor for this class": function factoryIsConstructor(){
+				assert.equal(new ConcatExpression().getFactory(), ConcatExpression);
+			}
+
+		},
+
+		"#evaluate()": {
+
+			"should return empty string if no operands were given; {$concat:[]}": function testEmpty(){
+				assert.equal(Expression.parseOperand({$concat:[]}).evaluate(), "");
+			},
+
+			"should return mystring if operands are my string; {$concat:[my, string]}": function testConcat(){
+				assert.equal(Expression.parseOperand({$concat:["my", "string"]}).evaluate(), "mystring");
+			},
+
+			"should return mystring if operands are my and $a; {$concat:[my,$a]}": function testFieldPath(){
+				assert.equal(Expression.parseOperand({$concat:["my","$a"]}).evaluate({a:"string"}), "mystring");
+			},
+
+			"should return null if an operand evaluates to null; {$concat:[my,$a]}": function testNull(){
+				assert.equal(Expression.parseOperand({$concat:["my","$a"]}).evaluate({a:null}), null);
+			}
+
+		}
+
+	}
+
+};
+
+if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);