Explorar o código

refs #5127: update projectDocSource and its corresponding test cases

Patrick Rigney %!s(int64=12) %!d(string=hai) anos
pai
achega
170c7c3990

+ 24 - 13
lib/pipeline/documentSources/ProjectDocumentSource.js

@@ -18,9 +18,12 @@ var ProjectDocumentSource = module.exports = function ProjectDocumentSource(ctx)
 }, klass = ProjectDocumentSource, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 }, klass = ProjectDocumentSource, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
 
 // DEPENDENCIES
 // DEPENDENCIES
-var Expression = require('../expressions/Expression');
-var ObjectExpression = require('../expressions/ObjectExpression');
-var Value = require('../Value');
+var Expression = require('../expressions/Expression'),
+	ObjectExpression = require('../expressions/ObjectExpression'),
+	Value = require('../Value'),
+	Variables = require('../expressions/Variables'),
+	VariablesIdGenerator = require('../expressions/VariablesIdGenerator'),
+	VariablesParseState = require('../expressions/VariablesParseState');
 
 
 klass.projectName = "$project";
 klass.projectName = "$project";
 
 
@@ -39,7 +42,7 @@ proto.getNext = function getNext(callback) {
 
 
 	this.source.getNext(function(err, input) {
 	this.source.getNext(function(err, input) {
 		if (err)
 		if (err)
-		return callback(null, err);
+			return callback(null, err);
 
 
 		if (input === DocumentSource.EOF)
 		if (input === DocumentSource.EOF)
 			return callback(null, DocumentSource.EOF);
 			return callback(null, DocumentSource.EOF);
@@ -47,13 +50,15 @@ proto.getNext = function getNext(callback) {
 		/* create the result document */
 		/* create the result document */
 		var out = {};
 		var out = {};
 
 
-		/*
-		* Use the ExpressionObject to create the base result.
-		*
-		* If we're excluding fields at the top level, leave out the _id if
-		* it is found, because we took care of it above.
-		*/
-		self.OE.addToDocument(out, input); // TODO: 'Variables' stuffs
+		/**
+		 * Use the ExpressionObject to create the base result.
+		 *
+		 * If we're excluding fields at the top level, leave out the _id if
+		 * it is found, because we took care of it above.
+		 **/
+		self._variables.setRoot(input);
+		self.OE.addToDocument(out, input, self._variables);
+		self._variables.clearRoot();
 
 
 		return callback(null, out);
 		return callback(null, out);
 	});
 	});
@@ -105,18 +110,24 @@ proto.sourceToJson = function sourceToJson(builder, explain) {
  **/
  **/
 klass.createFromJson = function(jsonElement, expCtx) {
 klass.createFromJson = function(jsonElement, expCtx) {
 	if (!(jsonElement instanceof Object) || jsonElement.constructor !== Object) throw new Error('Error 15969. Specification must be an object but was ' + typeof jsonElement);
 	if (!(jsonElement instanceof Object) || jsonElement.constructor !== Object) throw new Error('Error 15969. Specification must be an object but was ' + typeof jsonElement);
+
 	var objectContext = new Expression.ObjectCtx({
 	var objectContext = new Expression.ObjectCtx({
 		isDocumentOk: true,
 		isDocumentOk: true,
 		isTopLevel: true,
 		isTopLevel: true,
 		isInclusionOk: true
 		isInclusionOk: true
 	});
 	});
-	var project = new ProjectDocumentSource(expCtx);
+
+	var project = new ProjectDocumentSource(expCtx),
+		idGenerator = new VariablesIdGenerator(),
+		vps = new VariablesParseState(idGenerator);
+
 	project._raw = jsonElement;
 	project._raw = jsonElement;
-	var parsed = Expression.parseObject(jsonElement, objectContext);
+	var parsed = Expression.parseObject(jsonElement, objectContext, vps);
 	var exprObj = parsed;
 	var exprObj = parsed;
 	if (!exprObj instanceof ObjectExpression) throw new Error("16402, parseObject() returned wrong type of Expression");
 	if (!exprObj instanceof ObjectExpression) throw new Error("16402, parseObject() returned wrong type of Expression");
 	if (!exprObj.getFieldCount()) throw new Error("16403, $projection requires at least one output field");
 	if (!exprObj.getFieldCount()) throw new Error("16403, $projection requires at least one output field");
 	project.OE = exprObj;
 	project.OE = exprObj;
+	project._variables = new Variables(idGenerator.getIdCount());
 	return project;
 	return project;
 };
 };
 
 

+ 27 - 6
test/lib/pipeline/documentSources/ProjectDocumentSource.js

@@ -25,15 +25,14 @@ var createProject = function createProject(projection) {
 		};
 		};
 	}
 	}
 	var spec = {
 	var spec = {
-		"$project": projection
-	},
+			"$project": projection
+		},
 		specElement = projection,
 		specElement = projection,
 		project = ProjectDocumentSource.createFromJson(specElement);
 		project = ProjectDocumentSource.createFromJson(specElement);
 	checkJsonRepresentation(project, spec);
 	checkJsonRepresentation(project, spec);
 	return project;
 	return project;
 };
 };
 
 
-
 //TESTS
 //TESTS
 module.exports = {
 module.exports = {
 
 
@@ -73,6 +72,26 @@ module.exports = {
 				});
 				});
 			},
 			},
 
 
+			"iterator state accessors consistently report the source is exhausted": function assertExhausted() {
+				var cwc = new CursorDocumentSource.CursorWithContext();
+				var input = [{}];
+				cwc._cursor = new Cursor( input );
+				var cds = new CursorDocumentSource(cwc);
+				var pds = createProject();
+				pds.setSource(cds);
+				pds.getNext(function(err, actual) {
+					pds.getNext(function(err, actual1) {
+						assert.equal(DocumentSource.EOF, actual1);
+						pds.getNext(function(err, actual2) {
+							assert.equal(DocumentSource.EOF, actual2);
+							pds.getNext(function(err, actual3) {
+								assert.equal(DocumentSource.EOF, actual3);
+							});
+						});
+					});
+				});
+			},
+
 			"callback is required": function requireCallback() {
 			"callback is required": function requireCallback() {
 				var pds = createProject();
 				var pds = createProject();
 				assert.throws(pds.getNext.bind(pds));
 				assert.throws(pds.getNext.bind(pds));
@@ -80,11 +99,13 @@ module.exports = {
 
 
 			"should not return EOF when a document is still in cursor": function testNotEOFTrueIfDocPresent() {
 			"should not return EOF when a document is still in cursor": function testNotEOFTrueIfDocPresent() {
 				var cwc = new CursorDocumentSource.CursorWithContext();
 				var cwc = new CursorDocumentSource.CursorWithContext();
-				cwc._cursor = new Cursor( [{a: 1}] );
+				var input = [{_id: 0, a: 1}, {_id: 1, a: 2}];
+					cwc._cursor = new Cursor( input );
 				var cds = new CursorDocumentSource(cwc);
 				var cds = new CursorDocumentSource(cwc);
-				var pds = new ProjectDocumentSource();
+				var pds = createProject();
 				pds.setSource(cds);
 				pds.setSource(cds);
 				pds.getNext(function(err,actual) {
 				pds.getNext(function(err,actual) {
+					// first go round
 					assert.notEqual(actual, DocumentSource.EOF);
 					assert.notEqual(actual, DocumentSource.EOF);
 				});
 				});
 			},
 			},
@@ -267,4 +288,4 @@ module.exports = {
 
 
 };
 };
 
 
-if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);
+if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).grep(process.env.MOCHA_GREP || '').run(process.exit);