ProjectDocumentSource.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. "use strict";
  2. var assert = require("assert"),
  3. async = require("async"),
  4. DocumentSource = require("../../../../lib/pipeline/documentSources/DocumentSource"),
  5. ProjectDocumentSource = require("../../../../lib/pipeline/documentSources/ProjectDocumentSource"),
  6. CursorDocumentSource = require("../../../../lib/pipeline/documentSources/CursorDocumentSource"),
  7. Cursor = require("../../../../lib/Cursor");
  8. /**
  9. * Tests if the given rep is the same as what the pds resolves to as JSON.
  10. * MUST CALL WITH A PDS AS THIS (e.g. checkJsonRepresentation.call(this, rep) where this is a PDS)
  11. **/
  12. var checkJsonRepresentation = function checkJsonRepresentation(self, rep) {
  13. var pdsRep = {};
  14. self.sourceToJson(pdsRep, true);
  15. assert.deepEqual(pdsRep, rep);
  16. };
  17. var createProject = function createProject(projection) {
  18. //let projection be optional
  19. if (!projection) {
  20. projection = {
  21. a: true
  22. };
  23. }
  24. var spec = {
  25. "$project": projection
  26. },
  27. specElement = projection,
  28. project = ProjectDocumentSource.createFromJson(specElement);
  29. checkJsonRepresentation(project, spec);
  30. return project;
  31. };
  32. //TESTS
  33. module.exports = {
  34. "ProjectDocumentSource": {
  35. "constructor()": {
  36. "should not throw Error when constructing without args": function testConstructor() {
  37. assert.doesNotThrow(function() {
  38. new ProjectDocumentSource();
  39. });
  40. }
  41. },
  42. "#getSourceName()": {
  43. "should return the correct source name; $project": function testSourceName() {
  44. var pds = new ProjectDocumentSource();
  45. assert.strictEqual(pds.getSourceName(), "$project");
  46. }
  47. },
  48. "#getNext()": {
  49. "should return EOF": function testEOF(next) {
  50. var pds = createProject();
  51. pds.setSource({
  52. getNext: function getNext(cb) {
  53. return cb(null, DocumentSource.EOF);
  54. }
  55. });
  56. pds.getNext(function(err, doc) {
  57. assert.equal(DocumentSource.EOF, doc);
  58. next();
  59. });
  60. },
  61. "callback is required": function requireCallback() {
  62. var pds = createProject();
  63. assert.throws(pds.getNext.bind(pds));
  64. },
  65. "should not return EOF when a document is still in cursor": function testNotEOFTrueIfDocPresent() {
  66. var cwc = new CursorDocumentSource.CursorWithContext();
  67. cwc._cursor = new Cursor( [{a: 1}] );
  68. var cds = new CursorDocumentSource(cwc);
  69. var pds = new ProjectDocumentSource();
  70. pds.setSource(cds);
  71. pds.getNext(function(err,actual) {
  72. assert.notEqual(actual, DocumentSource.EOF);
  73. });
  74. },
  75. "can retrieve second document from source": function testAdvanceFirst() {
  76. var cwc = new CursorDocumentSource.CursorWithContext();
  77. var input = [{_id: 0, a: 1}, {_id: 1, a: 2}];
  78. cwc._cursor = new Cursor( input );
  79. var cds = new CursorDocumentSource(cwc);
  80. var pds = createProject();
  81. pds.setSource(cds);
  82. pds.getNext(function(err,val) {
  83. // eh, ignored
  84. pds.getNext(function(err,val) {
  85. assert.equal(2, val.a);
  86. });
  87. });
  88. },
  89. "should get the first document out of a cursor": function getCurrentCalledFirst() {
  90. var cwc = new CursorDocumentSource.CursorWithContext();
  91. var input = [{_id: 0, a: 1}];
  92. cwc._cursor = new Cursor( input );
  93. var cds = new CursorDocumentSource(cwc);
  94. var pds = createProject();
  95. pds.setSource(cds);
  96. pds.getNext(function(err, actual) {
  97. assert.equal(1, actual.a);
  98. });
  99. },
  100. "The a and c.d fields are included but the b field is not": function testFullProject1(next) {
  101. var cwc = new CursorDocumentSource.CursorWithContext();
  102. var input = [{
  103. _id: 0,
  104. a: 1,
  105. b: 1,
  106. c: {
  107. d: 1
  108. }
  109. }];
  110. cwc._cursor = new Cursor(input);
  111. var cds = new CursorDocumentSource(cwc);
  112. var pds = createProject({
  113. a: true,
  114. c: {
  115. d: true
  116. }
  117. }),
  118. expected = {a:1, c:{ d: 1 }};
  119. pds.setSource(cds);
  120. pds.getNext(function(err,val) {
  121. assert.deepEqual(expected, val);
  122. next();
  123. });
  124. },
  125. "Two documents": function testTwoDocumentsProject(next) {
  126. var cwc = new CursorDocumentSource.CursorWithContext();
  127. var input = [{
  128. a: 1,
  129. b: 2
  130. }, {
  131. a: 3,
  132. b: 4
  133. }],
  134. expected = [
  135. {a:1},
  136. {a:3},
  137. DocumentSource.EOF
  138. ];
  139. cwc._cursor = new Cursor(input);
  140. var cds = new CursorDocumentSource(cwc);
  141. var pds = createProject({
  142. a: true,
  143. c: {
  144. d: true
  145. }
  146. });
  147. pds.setSource(cds);
  148. async.series([
  149. pds.getNext.bind(pds),
  150. pds.getNext.bind(pds),
  151. pds.getNext.bind(pds),
  152. ],
  153. function(err,res) {
  154. assert.deepEqual(expected, res);
  155. next();
  156. }
  157. );
  158. }
  159. },
  160. "#optimize()": {
  161. "Optimize the projection": function optimizeProject() {
  162. var pds = createProject({
  163. a: {
  164. $and: [true]
  165. }
  166. });
  167. pds.optimize();
  168. checkJsonRepresentation(pds, {
  169. $project: {
  170. a: {
  171. $const: true
  172. }
  173. }
  174. });
  175. }
  176. },
  177. "#createFromJson()": {
  178. "should error if called with non-object": function testNonObjectPassed() {
  179. //String as arg
  180. assert.throws(function() {
  181. var pds = createProject("not an object");
  182. });
  183. //Date as arg
  184. assert.throws(function() {
  185. var pds = createProject(new Date());
  186. });
  187. //Array as arg
  188. assert.throws(function() {
  189. var pds = createProject([]);
  190. });
  191. //Empty args
  192. assert.throws(function() {
  193. var pds = ProjectDocumentSource.createFromJson();
  194. });
  195. //Top level operator
  196. assert.throws(function() {
  197. var pds = createProject({
  198. $add: []
  199. });
  200. });
  201. //Invalid spec
  202. assert.throws(function() {
  203. var pds = createProject({
  204. a: {
  205. $invalidOperator: 1
  206. }
  207. });
  208. });
  209. }
  210. },
  211. "#getDependencies()": {
  212. "should properly detect dependencies in project": function testGetDependencies() {
  213. var cwc = new CursorDocumentSource.CursorWithContext();
  214. var input = {
  215. a: true,
  216. x: '$b',
  217. y: {
  218. $and: ['$c', '$d']
  219. }
  220. };
  221. var pds = createProject(input);
  222. var dependencies = {};
  223. assert.equal(DocumentSource.GetDepsReturn.EXHAUSTIVE, pds.getDependencies(dependencies));
  224. assert.equal(5, Object.keys(dependencies).length);
  225. assert.ok(dependencies._id);
  226. assert.ok(dependencies.a);
  227. assert.ok(dependencies.b);
  228. assert.ok(dependencies.c);
  229. assert.ok(dependencies.d);
  230. }
  231. }
  232. }
  233. };
  234. if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);