瀏覽代碼

Fixes #995. AvgAccumulator ported with test cases. Skipped all of the shard centric stuff.

http://source.rd.rcg.local/trac/eagle6/changeset/1315/Eagle6_SVN
Spencer Rathbun 12 年之前
父節點
當前提交
9f0562d136
共有 2 個文件被更改,包括 148 次插入0 次删除
  1. 30 0
      lib/pipeline/accumulators/AvgAccumulator.js
  2. 118 0
      test/lib/pipeline/accumulators/AvgAccumulator.js

+ 30 - 0
lib/pipeline/accumulators/AvgAccumulator.js

@@ -0,0 +1,30 @@
+var AvgAccumulator = module.exports = (function(){
+
+	// Constructor
+	var klass = module.exports = function AvgAccumulator(){
+		this.subTotalName = "subTotal";
+		this.countName = "count";
+		this.totalIsANumber = true;
+		base.call(this);
+	}, SumAccumulator = require("./SumAccumulator"), base = SumAccumulator, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
+
+	proto.getFactory = function getFactory(){
+		return klass;	// using the ctor rather than a separate .create() method
+	};
+
+	proto.getValue = function getValue(){
+		if(this.totalIsANumber && this.count > 0)
+			return this.total/this.count;
+		else if (this.count === 0)
+			return 0;
+		else
+			throw new Error("$sum resulted in a non-numeric type");
+	};
+
+	proto.getOpName = function getOpName(){
+		return "$avg";
+	};
+
+	return klass;
+
+})();

+ 118 - 0
test/lib/pipeline/accumulators/AvgAccumulator.js

@@ -0,0 +1,118 @@
+var assert = require("assert"),
+	AvgAccumulator = require("../../../../lib/pipeline/accumulators/AvgAccumulator"),
+	FieldPathExpression = require("../../../../lib/pipeline/expressions/FieldPathExpression");
+
+
+function createAccumulator(){
+	var avgAccumulator = new AvgAccumulator();
+	avgAccumulator.addOperand(new FieldPathExpression("b") );
+	return avgAccumulator;
+}
+
+
+module.exports = {
+
+	"AvgAccumulator": {
+
+		"constructor()": {
+
+			"should not throw Error when constructing without args": function testConstructor(){
+				assert.doesNotThrow(function(){
+					new AvgAccumulator();
+				});
+			}
+
+		},
+
+		"#getOpName()": {
+
+			"should return the correct op name; $avg": function testOpName(){
+				assert.strictEqual(new AvgAccumulator().getOpName(), "$avg");
+			}
+
+		},
+
+		"#evaluate()": {
+
+			"should evaluate no documents": function testStuff(){
+				var avgAccumulator = createAccumulator();
+				avgAccumulator.evaluate();
+				assert.strictEqual(avgAccumulator.getValue(), 0);
+			},
+
+			"should evaluate one document with a field that is NaN": function testStuff(){
+				var avgAccumulator = createAccumulator();
+				avgAccumulator.evaluate({b:Number("foo")});
+				// NaN is unequal to itself
+				assert.notStrictEqual(avgAccumulator.getValue(), avgAccumulator.getValue());
+			},
+
+
+			"should evaluate one document and avg it's value": function testStuff(){
+				var avgAccumulator = createAccumulator();
+				avgAccumulator.evaluate({b:5});
+				assert.strictEqual(avgAccumulator.getValue(), 5);
+
+			},
+
+
+			"should evaluate and avg two ints": function testStuff(){
+				var avgAccumulator = createAccumulator();
+				avgAccumulator.evaluate({b:5});
+				avgAccumulator.evaluate({b:7});
+				assert.strictEqual(avgAccumulator.getValue(), 6);
+			},
+
+			"should evaluate and avg two ints overflow": function testStuff(){
+				var avgAccumulator = createAccumulator();
+				avgAccumulator.evaluate({b:Number.MAX_VALUE});
+				avgAccumulator.evaluate({b:Number.MAX_VALUE});
+				assert.strictEqual(Number.isFinite(avgAccumulator.getValue()), false);
+			},
+
+
+			"should evaluate and avg two negative ints": function testStuff(){
+				var avgAccumulator = createAccumulator();
+				avgAccumulator.evaluate({b:-5});
+				avgAccumulator.evaluate({b:-7});
+				assert.strictEqual(avgAccumulator.getValue(), -6);
+			},
+
+//TODO Not sure how to do this in Javascript
+//			"should evaluate and avg two negative ints overflow": function testStuff(){
+//				var avgAccumulator = createAccumulator();
+//				avgAccumulator.evaluate({b:Number.MIN_VALUE});
+//				avgAccumulator.evaluate({b:7});
+//				assert.strictEqual(avgAccumulator.getValue(), Number.MAX_VALUE);
+//			},
+//
+
+			"should evaluate and avg int and float": function testStuff(){
+				var avgAccumulator = createAccumulator();
+				avgAccumulator.evaluate({b:8.5});
+				avgAccumulator.evaluate({b:7});
+				assert.strictEqual(avgAccumulator.getValue(), 7.75);
+			},
+
+			"should evaluate and avg one Number and a NaN sum to NaN": function testStuff(){
+				var avgAccumulator = createAccumulator();
+				avgAccumulator.evaluate({b:8});
+				avgAccumulator.evaluate({b:Number("bar")});
+				// NaN is unequal to itself
+				assert.notStrictEqual(avgAccumulator.getValue(), avgAccumulator.getValue());
+			},
+
+			"should evaluate and avg a null value to 0": function testStuff(){
+				var avgAccumulator = createAccumulator();
+				avgAccumulator.evaluate({b:null});
+				assert.strictEqual(avgAccumulator.getValue(), 0);
+			}
+
+		}
+
+	}
+
+};
+
+if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);
+