ProjectDocumentSource.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. "use strict";
  2. var assert = require("assert"),
  3. DocumentSource = require("../../../../lib/pipeline/documentSources/DocumentSource"),
  4. ProjectDocumentSource = require("../../../../lib/pipeline/documentSources/ProjectDocumentSource"),
  5. CursorDocumentSource = require("../../../../lib/pipeline/documentSources/CursorDocumentSource"),
  6. Cursor = require("../../../../lib/Cursor");
  7. //HELPERS
  8. var assertExhausted = function assertExhausted(pds) {
  9. assert.ok(pds.eof());
  10. assert.ok(!pds.advance());
  11. };
  12. /**
  13. * Tests if the given rep is the same as what the pds resolves to as JSON.
  14. * MUST CALL WITH A PDS AS THIS (e.g. checkJsonRepresentation.call(this, rep) where this is a PDS)
  15. **/
  16. var checkJsonRepresentation = function checkJsonRepresentation(self, rep) {
  17. var pdsRep = {};
  18. self.sourceToJson(pdsRep, true);
  19. assert.deepEqual(pdsRep, rep);
  20. };
  21. var createProject = function createProject(projection) {
  22. //let projection be optional
  23. if(!projection){
  24. projection = {a:true};
  25. }
  26. var spec = {"$project": projection},
  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 throw Error when constructing with args": function testConstructor(){
  37. assert.throws(function(){
  38. new ProjectDocumentSource({ctx: [1,2]});
  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. "#eof()": {
  49. "should return same as this.pSource.eof": function testEOF(){
  50. var pds = new ProjectDocumentSource();
  51. pds.setSource({
  52. eof: function eof() {
  53. return true;
  54. }
  55. });
  56. assert.ok(pds.eof());
  57. },
  58. "should return !eof == true when a document is still in cursor": function testNotEOFTrueIfDocPresent() {
  59. var cwc = new CursorDocumentSource.CursorWithContext();
  60. cwc._cursor = new Cursor( [{a: 1}] );
  61. var cds = new CursorDocumentSource(cwc);
  62. var pds = new ProjectDocumentSource();
  63. pds.setSource(cds);
  64. assert.ok(!pds.eof());
  65. }
  66. },
  67. "#advance()": {
  68. "should return same as this.psource.advance": function testCallsThisPSourceAdvance() {
  69. var pds = new ProjectDocumentSource();
  70. pds.setSource({
  71. advance: function advance() {
  72. return true;
  73. }
  74. });
  75. assert.ok(pds.advance());
  76. },
  77. "can retrieve values from the project when advance is first function call": function testAdvanceFirst() {
  78. var cwc = new CursorDocumentSource.CursorWithContext();
  79. var input = [{_id: 0, a: 1}, {_id: 1, a: 2}];
  80. cwc._cursor = new Cursor( input );
  81. var cds = new CursorDocumentSource(cwc);
  82. var pds = createProject();
  83. pds.setSource(cds);
  84. assert.ok(pds.advance());
  85. assert.equal(2, pds.getCurrent().a);
  86. }
  87. },
  88. /* TODO : copy mongo tests, they will probably be more involved */
  89. "#getCurrent()": {
  90. "should work when getCurrent is the first function call": function getCurrentCalledFirst() {
  91. var cwc = new CursorDocumentSource.CursorWithContext();
  92. var input = [{_id: 0, a: 1}];
  93. cwc._cursor = new Cursor( input );
  94. var cds = new CursorDocumentSource(cwc);
  95. var pds = createProject();
  96. pds.setSource(cds);
  97. assert.ok(pds.getCurrent());
  98. assert.equal(1, pds.getCurrent().a);
  99. }
  100. },
  101. "combined": {
  102. "The a and c.d fields are included but the b field is not": function testFullProject1() {
  103. var cwc = new CursorDocumentSource.CursorWithContext();
  104. var input = [{_id:0,a:1,b:1,c:{d:1}}];
  105. cwc._cursor = new Cursor( input );
  106. var cds = new CursorDocumentSource(cwc);
  107. var pds = createProject({a:true, c:{d:true}});
  108. pds.setSource(cds);
  109. assert.ok(pds.getCurrent());
  110. assert.equal(1, pds.getCurrent().a);
  111. assert.ok(!pds.getCurrent().b);
  112. assert.equal(0, pds.getCurrent()._id);
  113. assert.equal(1, pds.getCurrent().c.d);
  114. },
  115. "Two documents": function testTwoDocumentsProject() {
  116. var cwc = new CursorDocumentSource.CursorWithContext();
  117. var input = [{a:1, b:2}, {a:3, b:4}];
  118. cwc._cursor = new Cursor( input );
  119. var cds = new CursorDocumentSource(cwc);
  120. var pds = createProject({a:true, c:{d:true}});
  121. pds.setSource(cds);
  122. assert.ok(!pds.eof());
  123. assert.equal(1, pds.getCurrent().a);
  124. assert.ok(!pds.getCurrent().b);
  125. assert.ok(pds.advance());
  126. assert.ok(!pds.eof());
  127. assert.equal(3, pds.getCurrent().a);
  128. assert.ok(!pds.getCurrent().b);
  129. assert.ok(!pds.advance());
  130. assertExhausted(pds);
  131. }
  132. },
  133. "#optimize()": {
  134. "Optimize the projection": function optimizeProject() {
  135. var pds = createProject({a:{$and: [true]}});
  136. pds.optimize();
  137. checkJsonRepresentation(pds, {$project:{a:{$const:true}}});
  138. }
  139. },
  140. "#createFromJson()": {
  141. "should error if called with non-object": function testNonObjectPassed() {
  142. //String as arg
  143. assert.throws(function() {
  144. var pds = createProject("not an object");
  145. });
  146. //Date as arg
  147. assert.throws(function() {
  148. var pds = createProject(new Date());
  149. });
  150. //Array as arg
  151. assert.throws(function() {
  152. var pds = createProject([]);
  153. });
  154. //Empty args
  155. assert.throws(function() {
  156. var pds = ProjectDocumentSource.createFromJson();
  157. });
  158. //Top level operator
  159. assert.throws(function() {
  160. var pds = createProject({$add: []});
  161. });
  162. //Invalid spec
  163. assert.throws(function() {
  164. var pds = createProject({a:{$invalidOperator:1}});
  165. });
  166. }
  167. },
  168. "#getDependencies()": {
  169. "should properly detect dependencies in project": function testGetDependencies(){
  170. var cwc = new CursorDocumentSource.CursorWithContext();
  171. var input = {a:true,x:'$b',y:{$and:['$c','$d']}};
  172. var pds = createProject(input);
  173. var deps = [];
  174. assert.equal(DocumentSource.GetDepsReturn.EXHAUSTIVE, pds.getDependencies(deps));
  175. assert.equal(5, deps.length);
  176. assert.equal(1, deps.filter(function(val) { return "_id" == val; }).length);
  177. assert.equal(1, deps.filter(function(val) { return "a" == val; }).length);
  178. assert.equal(1, deps.filter(function(val) { return "b" == val; }).length);
  179. assert.equal(1, deps.filter(function(val) { return "c" == val; }).length);
  180. assert.equal(1, deps.filter(function(val) { return "d" == val; }).length);
  181. }
  182. }
  183. }
  184. };
  185. if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);