Переглянути джерело

fixed various bugs in the current document sources and the pipeline to get the overall munge flow working. turned on unit test cases for munge. refs #934

http://source.rd.rcg.local/trac/eagle6/changeset/1335/Eagle6_SVN
Philip Murray 12 роки тому
батько
коміт
9e38098d17

+ 1 - 1
lib/Cursor.js

@@ -24,7 +24,7 @@ var Cursor = module.exports = (function(){
 				self.cachedData.push(data);
 			});
 		} else if (throughStreamOrArray.constructor === Array){
-			this.cachedData = throughStreamOrArray.splice(0);
+			this.cachedData = throughStreamOrArray.slice(0);
 		} else {
 			throw new Error("Cursor requires a stream-utils.ThroughStream or Array object.");
 		}

+ 2 - 1
lib/munge.js

@@ -17,7 +17,8 @@ var Munger = (function(){
 	proto.execute = function execute(inputs){
 		var result = {};
 		result.ok = this.pipeline.run(inputs, result);
-		return result;
+		//return result;	//TODO: figure out if we want mongo style result or a simpler one.
+		return result.result;
 	};
 
 	return klass;

+ 10 - 12
lib/pipeline/Pipeline.js

@@ -15,13 +15,13 @@ var Pipeline = module.exports = (function(){
 //		UnwindDocumentSource = require('./documentSources/UnwindDocumentSource');
 	
 	klass.StageDesc = {};//attaching this to the class for test cases
-	klass.StageDesc[LimitDocumentSource.limitName] = LimitDocumentSource;
-	klass.StageDesc[MatchDocumentSource.matchName] = MatchDocumentSource;
-	klass.StageDesc[ProjectDocumentSource.projectName] = ProjectDocumentSource;
-//	klass.StageDesc[GroupDocumentSource.groupName] = GroupDocumentSource;
-//	klass.StageDesc[SkipDocumentSource.skipName] = SkipDocumentSource;
-//	klass.StageDesc[SortDocumentSource.sortName] = SortDocumentSource;
-//	klass.StageDesc[UnwindDocumentSource.unwindName] = UnwindDocumentSource;
+	klass.StageDesc[LimitDocumentSource.limitName] = LimitDocumentSource.createFromJson;
+	klass.StageDesc[MatchDocumentSource.matchName] = MatchDocumentSource.createFromJson;
+	klass.StageDesc[ProjectDocumentSource.projectName] = ProjectDocumentSource.createFromJson;
+//	klass.StageDesc[GroupDocumentSource.groupName] = GroupDocumentSource.createFromJson;
+//	klass.StageDesc[SkipDocumentSource.skipName] = SkipDocumentSource.createFromJson;
+//	klass.StageDesc[SortDocumentSource.sortName] = SortDocumentSource.createFromJson;
+//	klass.StageDesc[UnwindDocumentSource.unwindName] = UnwindDocumentSource.createFromJson;
 	
     /**
      * Create a pipeline from the command.
@@ -50,13 +50,13 @@ var Pipeline = module.exports = (function(){
             // Create a DocumentSource pipeline stage from 'stageSpec'.
             var stageName = Object.keys(obj)[0],
 				stageSpec = obj[stageName],
-				Desc = klass.StageDesc[stageName];
+				desc = klass.StageDesc[stageName];
 				
-			if (!Desc){
+			if (!desc){
 				throw new Error("Unrecognized pipeline stage name: '" + stageName + "'; code 16435" );
 			}
 			
-            var stage = new Desc(stageSpec);
+            var stage = desc(stageSpec);
             //verify(stage);
             stage.setPipelineStep(iStep);
             sourceVector.push(stage);
@@ -151,7 +151,6 @@ var Pipeline = module.exports = (function(){
 	 * @param	{CursorDocumentSource}	source	the primary document source of the data
 	**/
 	proto.run = function run(result, source){
-		
         for(var i = 0, l = this.sourceVector.length; i<l; i++) {
 			var temp = this.sourceVector[i];
             temp.setSource(source);
@@ -170,7 +169,6 @@ var Pipeline = module.exports = (function(){
         var resultArray = [];
         for(var hasDoc = !source.eof(); hasDoc; hasDoc = source.advance()) {
             var document = source.getCurrent();
-
             /* add the document to the result set */
             resultArray.push(document);
             

+ 1 - 0
lib/pipeline/PipelineD.js

@@ -31,6 +31,7 @@ var PipelineD = module.exports = (function(){
 		//note that this is a deviation from the mongo implementation to facilitate pipeline reuse
 		sources.forEach(function(source){
 			source.reset();
+			source.pSource = null;
 		});
 
 		//TODO: should this go earlier in the execution so that we dont need to do it every time?

+ 15 - 6
lib/pipeline/documentSources/FilterBaseDocumentSource.js

@@ -30,7 +30,7 @@ var FilterBaseDocumentSource = module.exports = (function(){
 		}
 
 		while(this.hasNext) {
-			pDocument = this.pSource.getCurrent();
+			var pDocument = this.pSource.getCurrent();
 			this.hasNext = this.pSource.advance();
 
 			if (this.accept(pDocument)) {
@@ -39,7 +39,7 @@ var FilterBaseDocumentSource = module.exports = (function(){
 			}
 		}
 
-		this.pCurrent.reset();
+		this.pCurrent = null;
 	};
 
 	/**
@@ -50,7 +50,7 @@ var FilterBaseDocumentSource = module.exports = (function(){
 	proto.eof = function eof() {
 		if (this.unstarted)
 			this.findNext();
-		return (this.pCurrent.get() === null);
+		return (this.pCurrent === null);
 	};
 	
 	/**
@@ -74,7 +74,7 @@ var FilterBaseDocumentSource = module.exports = (function(){
 		* first will skip over the first item.
 		**/
 		this.findNext();
-		return (this.pCurrent.get() !== null);
+		return (this.pCurrent !== null);
 	};
 	
 	/**
@@ -86,8 +86,8 @@ var FilterBaseDocumentSource = module.exports = (function(){
 	proto.getCurrent = function getCurrent() {
 		if (this.unstarted)
 			this.findNext();
-		if (this.pCurrent.get() === null) throw new Error("This should never happen");
-		return pCurrent;
+		if (this.pCurrent === null) throw new Error("This should never happen");
+		return this.pCurrent;
 	};
 
 	/**
@@ -115,6 +115,15 @@ var FilterBaseDocumentSource = module.exports = (function(){
 	proto.toMatcherJson = function toMatcherJson(pBuilder) {
 		throw new Error("not implemented");
 	};
+    /**
+     * Reset the document source so that it is ready for a new stream of data.
+     * Note that this is a deviation from the mongo implementation.
+     * 
+     * @method	reset
+    **/
+	proto.reset = function reset(){
+		this.unstarted = true;
+	};
 
 	return klass;
 })();

+ 14 - 3
lib/pipeline/documentSources/LimitDocumentSource.js

@@ -104,16 +104,27 @@ var LimitDocumentSource = module.exports = (function(){
 	 *
 	 * @param {Number} JsonElement this thing is *called* Json, but it expects a number
 	**/
-	proto.createFromJson = function createFromJson(JsonElement) {
-		//if (!(JsonElement instanceof Number)) throw new Error("code 15957; the limit must be specified as a number");
+	klass.createFromJson = function createFromJson(JsonElement) {
+		if (typeof JsonElement !== "number") throw new Error("code 15957; the limit must be specified as a number");
 
-		var nextLimit = proto.getFactory();
+		var Limit = proto.getFactory(),
+			nextLimit = new Limit();
 
 		nextLimit.limit = JsonElement;
 		if ((nextLimit.limit <= 0) || isNaN(nextLimit.limit)) throw new Error("code 15958; the limit must be positive");
 
 		return nextLimit;
 	};
+	
+    /**
+     * Reset the document source so that it is ready for a new stream of data.
+     * Note that this is a deviation from the mongo implementation.
+     * 
+     * @method	reset
+    **/
+	proto.reset = function reset(){
+		this.count = 0;
+	};
 
 	return klass;
 })();

+ 7 - 7
lib/pipeline/documentSources/MatchDocumentSource.js

@@ -16,7 +16,7 @@ var MatchDocumentSource = module.exports = (function(){
 		this.matcher = sift(query);
 	}, base = require('./FilterBaseDocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
-	proto.extend = function extend(obj, withObj){
+	klass.extend = function extend(obj, withObj){
 		var args = Array.prototype.slice.call(arguments), lastArg = args[args.length - 1]; 
 		for(var i = 1, n = args.length; i < n; i++){
 			withObj = args[i];
@@ -24,7 +24,7 @@ var MatchDocumentSource = module.exports = (function(){
 				if(withObj.hasOwnProperty(key)){
 					var objVal = obj[key], withObjVal = withObj[key];
 					if(objVal instanceof Object && withObjVal.constructor === Object){
-						Object.extend(objVal, withObjVal, isRecursive);
+						klass.extend(objVal, withObjVal);
 					}else{
 						obj[key] = withObjVal;
 					}
@@ -53,7 +53,7 @@ var MatchDocumentSource = module.exports = (function(){
      * @param	{Boolean}	explain	create explain output
     **/
 	proto.sourceToJson = function sourceToJson(builder, explain) {
-		builder[this.matchName] = this.matcher.query;
+		builder[this.getSourceName()] = this.matcher.query;
 	};
 
 	/**
@@ -90,10 +90,10 @@ var MatchDocumentSource = module.exports = (function(){
 	* @param builder the builder to write to
 	**/
 	proto.toMatcherJson = function toMatcherJson(builder) {
-		this.extend(builder, this.matcher.query);
+		klass.extend(builder, this.matcher.query);
 	};
 
-	proto.uassertNoDisallowedClauses = function uassertNoDisallowedClauses(query) {
+	klass.uassertNoDisallowedClauses = function uassertNoDisallowedClauses(query) {
 		for(var key in query){
 			if(query.hasOwnProperty(key)){
 				// can't use the Matcher API because this would segfault the constructor
@@ -109,10 +109,10 @@ var MatchDocumentSource = module.exports = (function(){
 		}
 	}; 
 
-	proto.createFromJson = function createFromJson(JsonElement) {
+	klass.createFromJson = function createFromJson(JsonElement) {
 		if (!(JsonElement instanceof Object) || JsonElement.constructor !== Object) throw new Error("code 15959 ; the match filter must be an expression in an object");
 
-		this.uassertNoDisallowedClauses(JsonElement);
+		klass.uassertNoDisallowedClauses(JsonElement);
 
 		var matcher = new MatchDocumentSource(JsonElement);
 

+ 3 - 3
lib/pipeline/documentSources/ProjectDocumentSource.js

@@ -16,9 +16,9 @@ var ProjectDocumentSource = module.exports = (function(){
 	}, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
 	// DEPENDENCIES
-	var ObjectExpression = require('../expressions/OjectExpression');
+	var ObjectExpression = require('../expressions/ObjectExpression');
 	var Value = require('../Value');
-	var Expression = require('../expressions/Expresssion');
+	var Expression = require('../expressions/Expression');
 
 
 	/**
@@ -92,7 +92,7 @@ var ProjectDocumentSource = module.exports = (function(){
 	 * @method createFromJson
 	 * @return a ProjectDocumentSource instance
 	**/
-	proto.createFromJson = function(jsonElement, expCtx) {
+	klass.createFromJson = function(jsonElement, expCtx) {
 		if(! jsonElement instanceof Object) {
 			throw new Error('Error 15969. Specification must be an object but was ' + typeof jsonElement);
 		}

+ 3 - 3
package.json

@@ -39,8 +39,8 @@
 		"node": ">=0.8"
 	},
 	"config": {
-		"test_syntax": false,
-		"test_unit": false,
-		"test_coverage": false
+		"test_syntax": true,
+		"test_unit": true,
+		"test_coverage": true
 	}
 }

+ 19 - 29
test/lib/munge.js

@@ -1,5 +1,4 @@
-var jsext = require("jsext").install(),	//TODO: remove this...
-    assert = require("assert"),
+var assert = require("assert"),
 	munge = require("../../");
 
 module.exports = {
@@ -7,7 +6,6 @@ module.exports = {
 	"munge": {
 
 		"should be able to use an empty pipeline (no-op)": function(){
-console.debug("");
 			var i = [1, 2, 3],
 				p = [],
 				e = [1, 2, 3],
@@ -19,11 +17,11 @@ console.debug("");
 			assert.equal(JSON.stringify(munge(p, i)), JSON.stringify(e), "Alternate use of munge should yield the same results!");
 		},
 
-		"should be able to use a $skip operator": function(){
-console.debug("");
+
+		"should be able to use a $limit operator": function(){
 			var i = [{_id:0}, {_id:1}, {_id:2}, {_id:3}, {_id:4}, {_id:5}],
-				p = [{$skip:2}, {$skip:1}],	//testing w/ 2 ensures independent state variables
-				e = [{_id:3}, {_id:4}, {_id:5}],
+				p = [{$limit:2}],
+				e = [{_id:0}, {_id:1}],
 				munger = munge(p),
 				a = munger(i);
 			assert.equal(JSON.stringify(a), JSON.stringify(e), "Unexpected value!");
@@ -32,11 +30,10 @@ console.debug("");
 			assert.equal(JSON.stringify(munge(p, i)), JSON.stringify(e), "Alternate use of munge should yield the same results!");
 		},
 
-		"should be able to use a $limit operator": function(){
-console.debug("");
-			var i = [{_id:0}, {_id:1}, {_id:2}, {_id:3}, {_id:4}, {_id:5}],
-				p = [{$limit:2}],
-				e = [{_id:0}, {_id:1}],
+		"should be able to use a $match operator": function(){
+			var i = [{_id:0, e:1}, {_id:1, e:0}, {_id:2, e:1}, {_id:3, e:0}, {_id:4, e:1}, {_id:5, e:0}],
+				p = [{$match:{e:1}}],
+				e = [{_id:0, e:1}, {_id:2, e:1}, {_id:4, e:1}],
 				munger = munge(p),
 				a = munger(i);
 			assert.equal(JSON.stringify(a), JSON.stringify(e), "Unexpected value!");
@@ -44,12 +41,12 @@ console.debug("");
 			assert.equal(JSON.stringify(munger(i)), JSON.stringify(e), "Reuse of munger should yield the same results!");
 			assert.equal(JSON.stringify(munge(p, i)), JSON.stringify(e), "Alternate use of munge should yield the same results!");
 		},
-
-		"should be able to use a $skip and then a $limit operator together in the same pipeline": function(){
-console.debug("");
-			var i = [{_id:0, e:1}, {_id:1, e:0}, {_id:2, e:1}, {_id:3, e:0}, {_id:4, e:1}, {_id:5, e:0}],
-				p = [{$skip:2}, {$limit:1}],
-				e = [{_id:2, e:1}],
+		
+/*
+		"should be able to use a $skip operator": function(){
+			var i = [{_id:0}, {_id:1}, {_id:2}, {_id:3}, {_id:4}, {_id:5}],
+				p = [{$skip:2}, {$skip:1}],	//testing w/ 2 ensures independent state variables
+				e = [{_id:3}, {_id:4}, {_id:5}],
 				munger = munge(p),
 				a = munger(i);
 			assert.equal(JSON.stringify(a), JSON.stringify(e), "Unexpected value!");
@@ -57,12 +54,10 @@ console.debug("");
 			assert.equal(JSON.stringify(munger(i)), JSON.stringify(e), "Reuse of munger should yield the same results!");
 			assert.equal(JSON.stringify(munge(p, i)), JSON.stringify(e), "Alternate use of munge should yield the same results!");
 		},
-
-		"should be able to use a $match operator": function(){
-console.debug("");
+		"should be able to use a $skip and then a $limit operator together in the same pipeline": function(){
 			var i = [{_id:0, e:1}, {_id:1, e:0}, {_id:2, e:1}, {_id:3, e:0}, {_id:4, e:1}, {_id:5, e:0}],
-				p = [{$match:{e:1}}],
-				e = [{_id:0, e:1}, {_id:2, e:1}, {_id:4, e:1}],
+				p = [{$skip:2}, {$limit:1}],
+				e = [{_id:2, e:1}],
 				munger = munge(p),
 				a = munger(i);
 			assert.equal(JSON.stringify(a), JSON.stringify(e), "Unexpected value!");
@@ -71,8 +66,8 @@ console.debug("");
 			assert.equal(JSON.stringify(munge(p, i)), JSON.stringify(e), "Alternate use of munge should yield the same results!");
 		},
 
+
 		"should be able to use a $project operator": function(){
-console.debug("");
 			var i = [{_id:0, e:1}, {_id:1, e:0}, {_id:2, e:1}, {_id:3, e:0}, {_id:4, e:1}, {_id:5, e:0}],
 				p = [{$project:{e:1}}],
 				e = [{_id:0, e:1}, {_id:2, e:1}, {_id:4, e:1}],
@@ -86,9 +81,7 @@ console.debug("");
 
 //TODO: $project w/ expressions
 
-/*
 		"should be able to construct an instance with $unwind operators properly": function(){
-console.debug("");
 			var i = [
 					{_id:0, nodes:[
 						{one:[11], two:[2,2]},
@@ -132,11 +125,8 @@ console.debug("");
 						{_id:false}, {_id:true},
 						{_id:new Date("2012-10-15T15:48:55.181Z")}, {_id:new Date("2012-10-22T08:01:21.235Z")}
 					];
-			console.debug("\nINPUTS:\n", i);
-			console.debug("\nPIPELINE OPS:\n", p);
 			var a = munge(p, i);
 			assert.equal(JSON.stringify(a), JSON.stringify(e), "Unexpected value!");
-			console.debug("\n");
 		}
 */
 	}

+ 10 - 4
test/lib/pipeline/Pipeline.js

@@ -17,7 +17,7 @@ module.exports = {
 				
 				this.current = 5;
 				
-			}, base = require('../../../lib/pipeline/documentSources/DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
+			}, TestDocumentSource = klass, base = require('../../../lib/pipeline/documentSources/DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 			
 			
 			proto.coalesce = function(){
@@ -41,19 +41,25 @@ module.exports = {
 			proto.getCurrent = function(){
 				return this.current;
 			};
+			klass.createFromJson = function(options){
+				return new TestDocumentSource(options);
+			};
 			
 			return klass;
-		})();
+		})().createFromJson;
 		
 		//TODO:remove this once Sort is implemented!!!
 		Pipeline.SortDocumentSource = (function(){
 			var klass = function SortDocumentSource(){
 				
-			}, base = require('../../../lib/pipeline/documentSources/DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
+			}, SortDocumentSource = klass, base = require('../../../lib/pipeline/documentSources/DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 			klass.sortName = "$sort";
+			klass.createFromJson = function(options){
+				return new SortDocumentSource(options);
+			};
 			return klass;
 		})();
-		Pipeline.StageDesc.$sort = Pipeline.SortDocumentSource;
+		Pipeline.StageDesc.$sort = Pipeline.SortDocumentSource.createFromJson;
 			
 		},
 		"parseCommand": {

+ 10 - 4
test/lib/pipeline/PipelineD.js

@@ -21,7 +21,7 @@ module.exports = {
 				
 				this.current = 5;
 				
-			}, base = DocumentSource, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
+			}, TestDocumentSource = klass, base = DocumentSource, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 			
 			
 			proto.coalesce = function(){
@@ -55,19 +55,25 @@ module.exports = {
 				}
 				return DocumentSource.GetDepsReturn.EXHAUSTIVE;
 			};
+			klass.createFromJson = function(options){
+				return new TestDocumentSource(options);
+			};
 			
 			return klass;
-		})();
+		})().createFromJson;
 		
 		//TODO:remove this once Sort is implemented!!!
 		Pipeline.SortDocumentSource = (function(){
 			var klass = function SortDocumentSource(){
 				
-			}, base = require('../../../lib/pipeline/documentSources/DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
+			}, SortDocumentSource = klass, base = require('../../../lib/pipeline/documentSources/DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 			klass.sortName = "$sort";
+			klass.createFromJson = function(options){
+				return new SortDocumentSource(options);
+			};
 			return klass;
 		})();
-		Pipeline.StageDesc.$sort = Pipeline.SortDocumentSource;
+		Pipeline.StageDesc.$sort = Pipeline.SortDocumentSource.createFromJson;
 			
 		},
 		"prepareCursorSource": {

+ 2 - 3
test/lib/pipeline/documentSources/LimitDocumentSource.js

@@ -144,9 +144,8 @@ module.exports = {
 		"#createFromJson()": {
 
 			"should return a new LimitDocumentSource object from an input number": function createTest(){
-				var lds = new LimitDocumentSource();
-				var t = lds.createFromJson(5);
-				assert.strictEqual(t, LimitDocumentSource);
+				var t = LimitDocumentSource.createFromJson(5);
+				assert.strictEqual(t.constructor, LimitDocumentSource);
 				assert.strictEqual(t.limit, 5);
 			}
 

+ 1 - 2
test/lib/pipeline/documentSources/MatchDocumentSource.js

@@ -59,8 +59,7 @@ module.exports = {
 		"#createFromJson()": {
 
 			"should return a new MatchDocumentSource object from an input object": function createTest(){
-				var mds = new MatchDocumentSource({ location : { $in : ['Kentucky'] } });
-				var t = mds.createFromJson({ someval:{$exists:true} });
+				var t = MatchDocumentSource.createFromJson({ someval:{$exists:true} });
 				assert.strictEqual(t instanceof MatchDocumentSource, true);
 			}
 

+ 4 - 2
test/lib/pipeline/expressions/NaryExpression.js

@@ -120,7 +120,9 @@ module.exports = {
 				testableExpr.checkArgCount(3);
 			});
 		},
-
+		
+		//the following test case is eagerly awaiting ObjectExpression
+/*
 		"#addDependencies()": function testDependencies(){
 			var testableExpr = new TestableExpression();
 
@@ -139,7 +141,7 @@ module.exports = {
 			testableExpr.addOperand(Expression.parseObject({a:"$x",q:"$r"}, new Expression.ObjectCtx({isDocumentOk:1})));
 			assert.deepEqual(testableExpr.addDependencies([]), ["ab.c", "r", "x"]);
 		}
-
+*/
 	}
 
 };