| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 | 
							- "use strict";
 
- if (!module.parent) return require.cache[__filename] = 0, (new(require("mocha"))()).addFile(__filename).ui("exports").run(process.exit);
 
- var assert = require("assert"),
 
- 	async = require("async"),
 
- 	DocumentSource = require("../../../../lib/pipeline/documentSources/DocumentSource"),
 
- 	DepsTracker = require("../../../../lib/pipeline/DepsTracker"),
 
- 	UnwindDocumentSource = require("../../../../lib/pipeline/documentSources/UnwindDocumentSource"),
 
- 	CursorDocumentSource = require("../../../../lib/pipeline/documentSources/CursorDocumentSource"),
 
- 	ArrayRunner = require("../../../../lib/query/ArrayRunner");
 
- /**
 
-  * Tests if the given rep is the same as what the pds resolves to as JSON.
 
-  * MUST CALL WITH A PDS AS THIS (e.g. checkJsonRepresentation.call(this, rep) where this is a PDS)
 
-  **/
 
- function checkJsonRepresentation(self, rep) {
 
- 	var pdsRep = self.serialize(true);
 
- 	assert.deepEqual(pdsRep, rep);
 
- }
 
- function createUnwind(unwind) {
 
- 	//let unwind be optional
 
- 	if (!unwind) {
 
- 		unwind = "$a";
 
- 	}
 
- 	var spec = {$unwind: unwind},
 
- 		specElement = unwind,
 
- 		unwindDs = UnwindDocumentSource.createFromJson(specElement);
 
- 	checkJsonRepresentation(unwindDs, spec);
 
- 	return unwindDs;
 
- }
 
- function addSource(unwind, data) {
 
- 	var cds = new CursorDocumentSource(null, new ArrayRunner(data), null);
 
- 	unwind.setSource(cds);
 
- }
 
- function checkResults(data, expectedResults, path, next) {
 
- 	if (expectedResults instanceof Function)
 
- 		next = expectedResults, expectedResults = null, path = null;
 
- 	if (path instanceof Function)
 
- 		next = path, path = null;
 
- 	var unwind = createUnwind(path);
 
- 	addSource(unwind, data || []);
 
- 	expectedResults = expectedResults || [];
 
- 	expectedResults.push(null);
 
- 	//Load the results from the DocumentSourceUnwind
 
- 	var docs = [], i = 0;
 
- 	async.doWhilst(
 
- 		function(cb) {
 
- 			unwind.getNext(function(err, val) {
 
- 				docs[i] = val;
 
- 				return cb(err);
 
- 			});
 
- 		},
 
- 		function() {
 
- 			return docs[i++] !== null;
 
- 		},
 
- 		function(err) {
 
- 			assert.deepEqual(expectedResults, docs);
 
- 			next();
 
- 		}
 
- 	);
 
- }
 
- function throwsException(data, path, expectedResults) {
 
- 	assert.throws(function () {
 
- 		checkResults(data, path, expectedResults);
 
- 	});
 
- }
 
- //TESTS
 
- module.exports = {
 
- 	"UnwindDocumentSource": {
 
- 		"constructor()": {
 
- 			"should not throw Error when constructing without args": function (){
 
- 				assert.doesNotThrow(function(){
 
- 					new UnwindDocumentSource();
 
- 				});
 
- 			}
 
- 		},
 
- 		"#getSourceName()": {
 
- 			"should return the correct source name; $unwind": function (){
 
- 				var pds = new UnwindDocumentSource();
 
- 				assert.strictEqual(pds.getSourceName(), "$unwind");
 
- 			}
 
- 		},
 
- 		"#getNext()": {
 
- 			"should return EOF if source is empty": function (next){
 
- 				var pds = createUnwind();
 
- 				addSource(pds, []);
 
- 				pds.getNext(function(err,doc) {
 
- 					assert.strictEqual(doc, null);
 
- 					next();
 
- 				});
 
- 			},
 
- 			"should return document if source documents exist": function (next){
 
- 				var pds = createUnwind();
 
- 				addSource(pds, [{_id:0, a:[1]}]);
 
- 				pds.getNext(function(err,doc) {
 
- 					assert.notStrictEqual(doc, null);
 
- 					next();
 
- 				});
 
- 			},
 
- 			"should return document if source documents exist and advance the source": function (next){
 
- 				var pds = createUnwind();
 
- 				addSource(pds, [{_id:0, a:[1,2]}]);
 
- 				pds.getNext(function(err,doc) {
 
- 					assert.notStrictEqual(doc, null);
 
- 					assert.strictEqual(doc.a, 1);
 
- 					pds.getNext(function(err,doc) {
 
- 						assert.strictEqual(doc.a, 2);
 
- 						next();
 
- 					});
 
- 				});
 
- 			},
 
- 			"should return unwound documents": function (next){
 
- 				var pds = createUnwind();
 
- 				addSource(pds, [{_id:0, a:[1,2]}]);
 
- 				var docs = [], i = 0;
 
- 				async.doWhilst(
 
- 					function(cb) {
 
- 						pds.getNext(function(err, val) {
 
- 							docs[i] = val;
 
- 							return cb(err);
 
- 						});
 
- 					},
 
- 					function() {
 
- 						return docs[i++] !== null;
 
- 					},
 
- 					function(err) {
 
- 						assert.deepEqual([{_id:0, a:1},{_id:0, a:2},null], docs);
 
- 						next();
 
- 					}
 
- 				);
 
- 			},
 
- 			"A document without the unwind field produces no results.": function (next){
 
- 				checkResults([{}],next);
 
- 			},
 
- 			"A document with a null field produces no results.": function (next){
 
- 				checkResults([{a:null}],next);
 
- 			},
 
- 			"A document with an empty array produces no results.": function (next){
 
- 				checkResults([{a:[]}],next);
 
- 			},
 
- 			"A document with a number field produces a UserException.": function (next){
 
- 				throwsException([{a:1}],next);
 
- 				next();
 
- 			},
 
- 			"An additional document with a number field produces a UserException.": function (next){
 
- 				throwsException([{a:[1]}, {a:1}],next);
 
- 				next();
 
- 			},
 
- 			"A document with a string field produces a UserException.": function (next){
 
- 				throwsException([{a:"foo"}],next);
 
- 				next();
 
- 			},
 
- 			"A document with an object field produces a UserException.": function (next){
 
- 				throwsException([{a:{}}],next);
 
- 				next();
 
- 			},
 
- 			"Unwind an array with one value.": function (next){
 
- 				checkResults(
 
- 					[{_id:0, a:[1]}],
 
- 					[{_id:0,a:1}],
 
- 					next
 
- 				);
 
- 			},
 
- 			"Unwind an array with two values.": function (next){
 
- 				checkResults(
 
- 					[{_id:0, a:[1, 2]}],
 
- 					[{_id:0,a:1}, {_id:0,a:2}],
 
- 					next
 
- 				);
 
- 			},
 
- 			"Unwind an array with two values, one of which is null.": function (next){
 
- 				checkResults(
 
- 					[{_id:0, a:[1, null]}],
 
- 					[{_id:0,a:1}, {_id:0,a:null}],
 
- 					next
 
- 				);
 
- 			},
 
- 			"Unwind two documents with arrays.": function (next){
 
- 				checkResults(
 
- 					[{_id:0, a:[1,2]}, {_id:0, a:[3,4]}],
 
- 					[{_id:0,a:1}, {_id:0,a:2}, {_id:0,a:3}, {_id:0,a:4}],
 
- 					next
 
- 				);
 
- 			},
 
- 			"Unwind an array in a nested document.": function (next){
 
- 				checkResults(
 
- 					[{_id:0,a:{b:[1,2],c:3}}],
 
- 					[{_id:0,a:{b:1,c:3}},{_id:0,a:{b:2,c:3}}],
 
- 					"$a.b",
 
- 					next
 
- 				);
 
- 			},
 
- 			"A missing array (that cannot be nested below a non object field) produces no results.": function (next){
 
- 				checkResults(
 
- 					[{_id:0,a:4}],
 
- 					[],
 
- 					"$a.b",
 
- 					next
 
- 				);
 
- 			},
 
- 			"Unwind an array in a doubly nested document.": function (next){
 
- 				checkResults(
 
- 					[{_id:0,a:{b:{d:[1,2],e:4},c:3}}],
 
- 					[{_id:0,a:{b:{d:1,e:4},c:3}},{_id:0,a:{b:{d:2,e:4},c:3}}],
 
- 					"$a.b.d",
 
- 					next
 
- 				);
 
- 			},
 
- 			"Unwind several documents in a row.": function (next){
 
- 				checkResults(
 
- 					[
 
- 						{_id:0,a:[1,2,3]},
 
- 						{_id:1},
 
- 						{_id:2},
 
- 						{_id:3,a:[10,20]},
 
- 						{_id:4,a:[30]}
 
- 					],
 
- 					[
 
- 						{_id:0,a:1},
 
- 						{_id:0,a:2},
 
- 						{_id:0,a:3},
 
- 						{_id:3,a:10},
 
- 						{_id:3,a:20},
 
- 						{_id:4,a:30}
 
- 					],
 
- 					next
 
- 				);
 
- 			},
 
- 			"Unwind several more documents in a row.": function (next){
 
- 				checkResults(
 
- 					[
 
- 						{_id:0,a:null},
 
- 						{_id:1},
 
- 						{_id:2,a:["a","b"]},
 
- 						{_id:3},
 
- 						{_id:4,a:[1,2,3]},
 
- 						{_id:5,a:[4,5,6]},
 
- 						{_id:6,a:[7,8,9]},
 
- 						{_id:7,a:[]}
 
- 					],
 
- 					[
 
- 						{_id:2,a:"a"},
 
- 						{_id:2,a:"b"},
 
- 						{_id:4,a:1},
 
- 						{_id:4,a:2},
 
- 						{_id:4,a:3},
 
- 						{_id:5,a:4},
 
- 						{_id:5,a:5},
 
- 						{_id:5,a:6},
 
- 						{_id:6,a:7},
 
- 						{_id:6,a:8},
 
- 						{_id:6,a:9}
 
- 					],
 
- 					next
 
- 				);
 
- 			}
 
- 		},
 
- 		"#createFromJson()": {
 
- 			"should error if called with non-string": function testNonObjectPassed() {
 
- 				//Date as arg
 
- 				assert.throws(function() {
 
- 					createUnwind(new Date());
 
- 				});
 
- 				//Array as arg
 
- 				assert.throws(function() {
 
- 					createUnwind([]);
 
- 				});
 
- 				//Empty args
 
- 				assert.throws(function() {
 
- 					UnwindDocumentSource.createFromJson();
 
- 				});
 
- 				//Top level operator
 
- 				assert.throws(function() {
 
- 					createUnwind({$add: []});
 
- 				});
 
- 			}
 
- 		},
 
- 		"#getDependencies": {
 
- 			"should get dependent field paths": function () {
 
- 				var pds = createUnwind("$x.y.z"),
 
- 					deps = new DepsTracker();
 
- 				assert.strictEqual(pds.getDependencies(deps), DocumentSource.GetDepsReturn.SEE_NEXT);
 
- 				assert.deepEqual(deps.fields, {"x.y.z":1});
 
- 			}
 
- 		}
 
- 	}
 
- };
 
 
  |