ProjectDocumentSource.js 8.1 KB

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