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

Merge branch 'feature/mongo_2.6.5_documentSource_Project' into feature/mongo_2.6.5_documentSource_SortDocumentSource

David Aebersold 11 роки тому
батько
коміт
bf5a25684b

+ 37 - 42
lib/pipeline/documentSources/ProjectDocumentSource.js

@@ -10,11 +10,12 @@ var DocumentSource = require('./DocumentSource');
  * @constructor
  * @param [ctx] {ExpressionContext}
  **/
-var ProjectDocumentSource = module.exports = function ProjectDocumentSource(ctx){
-	if (arguments.length > 1) throw new Error("up to one arg expected");
+var ProjectDocumentSource = module.exports = function ProjectDocumentSource(ctx, exprObj){
+	if (arguments.length > 2) throw new Error("up to two args expected");
 	base.call(this, ctx);
-	this.OE = new ObjectExpression();
+	this.OE = new ObjectExpression(exprObj);
 	this._raw = undefined;
+	this._variables = undefined;
 }, klass = ProjectDocumentSource, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
 // DEPENDENCIES
@@ -69,11 +70,11 @@ proto.getNext = function getNext(callback) {
 };
 
 /**
- * Returns the object that was used to construct the ProjectDocumentSource
- * @return {object} the object that was used to construct the ProjectDocumentSource
+ * Optimizes the internal ObjectExpression
+ * @return
  **/
-proto.getRaw = function getRaw() {
-	return this._raw;
+proto.optimize = function optimize() {
+	this.OE = this.OE.optimize();
 };
 
 proto.serialize = function serialize(explain) {
@@ -82,38 +83,13 @@ proto.serialize = function serialize(explain) {
 	return out;
 };
 
-/**
- * Optimizes the internal ObjectExpression
- * @return
- **/
-proto.optimize = function optimize() {
-	this.OE.optimize();
-};
-
-proto.toJSON = function toJSON(){
-	var obj = {};
-	this.sourceToJson(obj);
-	return obj;
-};
-
-/**
- * Places a $project key inside the builder object with value of this.OE
- * @method sourceToJson
- * @param {builder} An object (was ported from BsonBuilder)
- * @return
- **/
-proto.sourceToJson = function sourceToJson(builder, explain) {
-	var insides = this.OE.toJSON(true);
-	builder[this.getSourceName()] = insides;
-};
-
 /**
  * Builds a new ProjectDocumentSource from an object
  * @method createFromJson
  * @return {ProjectDocmentSource} a ProjectDocumentSource instance
  **/
-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);
+klass.createFromJson = function(elem, expCtx) {
+	if (!(elem instanceof Object) || elem.constructor !== Object) throw new Error('Error 15969. Specification must be an object but was ' + typeof elem);
 
 	var objectContext = new Expression.ObjectCtx({
 		isDocumentOk: true,
@@ -121,17 +97,22 @@ klass.createFromJson = function(jsonElement, expCtx) {
 		isInclusionOk: true
 	});
 
-	var project = new ProjectDocumentSource(expCtx),
-		idGenerator = new VariablesIdGenerator(),
-		vps = new VariablesParseState(idGenerator);
+	var idGenerator = new VariablesIdGenerator(),
+		vps = new VariablesParseState(idGenerator),
+		parsed = Expression.parseObject(elem, objectContext, vps),
+		exprObj = parsed;
 
-	project._raw = jsonElement;
-	var parsed = Expression.parseObject(jsonElement, objectContext, vps);
-	var exprObj = parsed;
 	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");
-	project.OE = exprObj;
+	//if (!exprObj.getFieldCount() ) throw new Error("uassert 16403: $project requires at least one output field");
+
+	var project = new ProjectDocumentSource(expCtx, exprObj);
 	project._variables = new Variables(idGenerator.getIdCount());
+
+	var projectObj = elem
+	project.OE = exprObj;
+
+	project._raw = elem;
+
 	return project;
 };
 
@@ -145,3 +126,17 @@ proto.getDependencies = function getDependencies(deps) {
 	this.OE.addDependencies(deps, path);
 	return base.GetDepsReturn.EXHAUSTIVE;
 };
+
+/**
+ * Returns the object that was used to construct the ProjectDocumentSource
+ * @return {object} the object that was used to construct the ProjectDocumentSource
+ **/
+proto.getRaw = function getRaw() {
+	return this._raw;
+};
+
+proto.toJSON = function toJSON(){
+	var obj = {};
+	this.sourceToJson(obj);
+	return obj;
+};

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

@@ -94,7 +94,7 @@ klass.parseObject = function parseObject(obj, ctx, vps) {
 		OPERATOR = 2,
 		kind = UNKNOWN;
 
-	if (obj === undefined || obj === null || (obj instanceof Object && Object.keys(obj).length === 0)) return new ObjectExpression();
+	if (obj === undefined || obj === null || (obj instanceof Object && Object.keys(obj).length === 0)) return new ObjectExpression({});
 	var fieldNames = Object.keys(obj);
 	for (var fieldCount = 0, n = fieldNames.length; fieldCount < n; ++fieldCount) {
 		var fieldName = fieldNames[fieldCount];

+ 25 - 8
test/lib/pipeline/documentSources/ProjectDocumentSource.js

@@ -4,7 +4,9 @@ var assert = require("assert"),
 	DocumentSource = require("../../../../lib/pipeline/documentSources/DocumentSource"),
 	ProjectDocumentSource = require("../../../../lib/pipeline/documentSources/ProjectDocumentSource"),
 	CursorDocumentSource = require("../../../../lib/pipeline/documentSources/CursorDocumentSource"),
-	Cursor = require("../../../../lib/Cursor");
+	Cursor = require("../../../../lib/Cursor"),
+	TestBase = require("./TestBase"),
+	And = require("../../../../lib/pipeline/expressions/AndExpression");
 
 
 /**
@@ -12,8 +14,7 @@ var assert = require("assert"),
  *   MUST CALL WITH A PDS AS THIS (e.g. checkJsonRepresentation.call(this, rep) where this is a PDS)
  **/
 var checkJsonRepresentation = function checkJsonRepresentation(self, rep) {
-	var pdsRep = {};
-	self.sourceToJson(pdsRep, true);
+	var pdsRep = self.serialize();
 	assert.deepEqual(pdsRep, rep);
 };
 
@@ -28,9 +29,9 @@ var createProject = function createProject(projection) {
 			"$project": projection
 		},
 		specElement = projection,
-		project = ProjectDocumentSource.createFromJson(specElement);
-	checkJsonRepresentation(project, spec);
-	return project;
+		_project = ProjectDocumentSource.createFromJson(specElement);
+	checkJsonRepresentation(_project, spec);
+	return _project;
 };
 
 //TESTS
@@ -38,12 +39,27 @@ module.exports = {
 
 	"ProjectDocumentSource": {
 
+		"mongo tests": {
+			"Inclusion": function() {
+				var test = new TestBase();
+				//client.insert( ns, fromjson( "{_id:0,a:1,b:1,c:{d:1}}" ) );
+				test.createSource();
+				test.createProject();
+			}
+		},
+
 		"constructor()": {
 
 			"should not throw Error when constructing without args": function testConstructor() {
 				assert.doesNotThrow(function() {
 					new ProjectDocumentSource();
 				});
+			},
+
+			"should throw Error when constructing with more than 1 arg": function testConstructor() {
+				assert.throws(function() {
+					new ProjectDocumentSource("a", "b", "c");
+				});
 			}
 
 		},
@@ -60,7 +76,7 @@ module.exports = {
 		"#getNext()": {
 
 			"should return EOF": function testEOF(next) {
-				var pds = createProject();
+				var pds = createProject({});
 				pds.setSource({
 					getNext: function getNext(cb) {
 						return cb(null, DocumentSource.EOF);
@@ -141,7 +157,7 @@ module.exports = {
 			"The a and c.d fields are included but the b field is not": function testFullProject1(next) {
 				var cwc = new CursorDocumentSource.CursorWithContext();
 				var input = [{
-					_id: 0,
+					_id:1,
 					a: 1,
 					b: 1,
 					c: {
@@ -151,6 +167,7 @@ module.exports = {
 				cwc._cursor = new Cursor(input);
 				var cds = new CursorDocumentSource(cwc);
 				var pds = createProject({
+						_id: 0,
 						a: true,
 						c: {
 							d: true

+ 47 - 0
test/lib/pipeline/documentSources/TestBase.js

@@ -0,0 +1,47 @@
+var TestBase = (function() {
+	var klass = function TestBase(overrides) {
+			//NOTE: DEVIATION FROM MONGO: using this base class to make things easier to initialize
+			for (var key in overrides){
+				this[key] = overrides[key];
+			}
+		},
+		proto = klass.prototype;
+	proto.createSource = function() {
+		//TODO: Fix this once we know proper API
+		this._source = CursorDocumentSource.create();
+	};
+	proto.source = function() {
+		return this._source;
+	};
+	proto.createProject = function(projection) {
+		projection = projection || {a:true};
+		var spec = {$project:projection};
+		this._project = ProjectDocumentSource(spec /*,ctx()*/);
+		this.checkJsonRepresentation(spec);
+		this._project.setSource(this.source());
+	};
+	proto.project = function() {
+		return this._project;
+	};
+	proto.assertExhausted = function() {
+		var self = this;
+		self._project.getNext(function(err, input1) {
+			assert.strictEqual(input, DocumentSource.EOF);
+			self._project.getNext(function(err, input2) {
+				assert.strictEqual(input2, DocumentSource.EOF);
+				self._project.getNext(function(err, input3) {
+					assert.strictEqual(input3, DocumentSource.EOF);
+				});
+			});
+		});
+	};
+	proto.checkJsonRepresentation = function() {
+		var arr = [];
+		this._project.serializeToArray(arr);
+		var generatedSpec = arr[0];
+		assert.deepEqual(generatedSpec, spec);
+	};
+	return klass;
+})();
+
+module.exports = TestBase;