| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 | 
							- "use strict";
 
- /**
 
-  * The base class for all n-ary `Expression`s
 
-  * @class NaryExpression
 
-  * @extends mungedb-aggregate.pipeline.expressions.Expression
 
-  * @namespace mungedb-aggregate.pipeline.expressions
 
-  * @module mungedb-aggregate
 
-  * @constructor
 
-  */
 
- var NaryExpression = module.exports = function NaryExpression() {
 
- 	if (arguments.length !== 0) throw new Error("Zero args expected");
 
- 	this.operands = [];
 
- 	base.call(this);
 
- }, klass = NaryExpression, Expression = require("./Expression"), base = Expression, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}}); //jshint ignore:line
 
- var Variables = require("./Variables"),
 
- 	ConstantExpression = require("./ConstantExpression");
 
- proto.optimize = function optimize() {
 
- 	var n = this.operands.length;
 
- 	// optimize sub-expressions and count constants
 
- 	var constCount = 0;
 
- 	for (var i = 0; i < n; ++i) {
 
- 		var optimized = this.operands[i].optimize();
 
- 		// substitute the optimized expression
 
- 		this.operands[i] = optimized;
 
- 		// check to see if the result was a constant
 
- 		if (optimized instanceof ConstantExpression) {
 
- 			constCount++;
 
- 		}
 
- 	}
 
- 	// If all the operands are constant, we can replace this expression with a constant. Using
 
- 	// an empty Variables since it will never be accessed.
 
- 	if (constCount === n) {
 
- 		var emptyVars = new Variables(),
 
- 			result = this.evaluateInternal(emptyVars),
 
- 			replacement = ConstantExpression.create(result);
 
- 		return replacement;
 
- 	}
 
- 	// Remaining optimizations are only for associative and commutative expressions.
 
- 	if(!this.isAssociativeAndCommutative()) {
 
- 		return this;
 
- 	}
 
- 	// Process vpOperand to split it into constant and nonconstant vectors.
 
- 	// This can leave vpOperand in an invalid state that is cleaned up after the loop.
 
- 	var constExprs = [],
 
- 		nonConstExprs = [];
 
- 	for (i = 0; i < this.operands.length; ++i) { // NOTE: vpOperand grows in loop
 
- 		var expr = this.operands[i];
 
- 		if (expr instanceof ConstantExpression) {
 
- 			constExprs.push(expr);
 
- 		} else {
 
- 			// If the child operand is the same type as this, then we can
 
- 			// extract its operands and inline them here because we know
 
- 			// this is commutative and associative.  We detect sameness of
 
- 			// the child operator by checking for equality of the opNames
 
- 			var nary = expr instanceof NaryExpression ? expr : undefined;
 
- 			if (!nary || nary.getOpName() !== this.getOpName()) {
 
- 				nonConstExprs.push(expr);
 
- 			} else {
 
- 				// same expression, so flatten by adding to vpOperand which
 
- 				// will be processed later in this loop.
 
- 				Array.prototype.push.apply(this.operands, nary.operands);
 
- 			}
 
- 		}
 
- 	}
 
- 	// collapse all constant expressions (if any)
 
- 	var constValue;
 
- 	if (constExprs.length > 0) {
 
- 		this.operands = constExprs;
 
- 		var emptyVars2 = new Variables();
 
- 		constValue = this.evaluateInternal(emptyVars2);
 
- 	}
 
- 	// now set the final expression list with constant (if any) at the end
 
- 	this.operands = nonConstExprs;
 
- 	if (constExprs.length > 0) {
 
- 		this.operands.push(ConstantExpression.create(constValue));
 
- 	}
 
- 	return this;
 
- };
 
- proto.addDependencies = function addDependencies(deps, path) {
 
- 	for (var i = 0, l = this.operands.length; i < l; ++i) {
 
- 		this.operands[i].addDependencies(deps);
 
- 	}
 
- };
 
- /**
 
-  * Add an operand to the n-ary expression.
 
-  * @method addOperand
 
-  * @param expr the expression to add
 
-  */
 
- proto.addOperand = function addOperand(expr) {
 
- 	this.operands.push(expr);
 
- };
 
- proto.serialize = function serialize(explain) {
 
- 	var nOperand = this.operands.length,
 
- 		array = [];
 
- 	// build up the array
 
- 	for (var i = 0; i < nOperand; i++) {
 
- 		array.push(this.operands[i].serialize(explain));
 
- 	}
 
- 	var obj = {};
 
- 	obj[this.getOpName()] = array;
 
- 	return obj;
 
- };
 
- proto.isAssociativeAndCommutative = function isAssociativeAndCommutative() {
 
- 	return false;
 
- };
 
- /**
 
-  * Get the name of the operator.
 
-  * @method getOpName
 
-  * @returns the name of the operator; this string belongs to the class
 
-  *  implementation, and should not be deleted
 
-  *  and should not
 
-  */
 
- proto.getOpName = function getOpName() {
 
- 	throw new Error("NOT IMPLEMENTED BY INHERITOR");
 
- };
 
- /**
 
-  * Allow subclasses the opportunity to validate arguments at parse time.
 
-  * @method validateArguments
 
-  * @param {[type]} args [description]
 
-  */
 
- proto.validateArguments = function validateArguments(args) {};
 
- klass.parseArguments = function parseArguments(exprElement, vps) {
 
- 	var out = [];
 
- 	if (exprElement instanceof Array) {
 
- 		for (var ii = 0; ii < exprElement.length; ii++) {
 
- 			out.push(Expression.parseOperand(exprElement[ii], vps));
 
- 		}
 
- 	} else {
 
- 		out.push(Expression.parseOperand(exprElement, vps));
 
- 	}
 
- 	return out;
 
- };
 
 
  |