ProjectDocumentSource.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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. "iterator state accessors consistently report the source is exhausted": function assertExhausted() {
  62. var cwc = new CursorDocumentSource.CursorWithContext();
  63. var input = [{}];
  64. cwc._cursor = new Cursor( input );
  65. var cds = new CursorDocumentSource(cwc);
  66. var pds = createProject();
  67. pds.setSource(cds);
  68. pds.getNext(function(err, actual) {
  69. pds.getNext(function(err, actual1) {
  70. assert.equal(DocumentSource.EOF, actual1);
  71. pds.getNext(function(err, actual2) {
  72. assert.equal(DocumentSource.EOF, actual2);
  73. pds.getNext(function(err, actual3) {
  74. assert.equal(DocumentSource.EOF, actual3);
  75. });
  76. });
  77. });
  78. });
  79. },
  80. "callback is required": function requireCallback() {
  81. var pds = createProject();
  82. assert.throws(pds.getNext.bind(pds));
  83. },
  84. "should not return EOF when a document is still in cursor": function testNotEOFTrueIfDocPresent() {
  85. var cwc = new CursorDocumentSource.CursorWithContext();
  86. var input = [{_id: 0, a: 1}, {_id: 1, a: 2}];
  87. cwc._cursor = new Cursor( input );
  88. var cds = new CursorDocumentSource(cwc);
  89. var pds = createProject();
  90. pds.setSource(cds);
  91. pds.getNext(function(err,actual) {
  92. // first go round
  93. assert.notEqual(actual, DocumentSource.EOF);
  94. });
  95. },
  96. "can retrieve second document from source": function testAdvanceFirst() {
  97. var cwc = new CursorDocumentSource.CursorWithContext();
  98. var input = [{_id: 0, a: 1}, {_id: 1, a: 2}];
  99. cwc._cursor = new Cursor( input );
  100. var cds = new CursorDocumentSource(cwc);
  101. var pds = createProject();
  102. pds.setSource(cds);
  103. pds.getNext(function(err,val) {
  104. // eh, ignored
  105. pds.getNext(function(err,val) {
  106. assert.equal(2, val.a);
  107. });
  108. });
  109. },
  110. "should get the first document out of a cursor": function getCurrentCalledFirst() {
  111. var cwc = new CursorDocumentSource.CursorWithContext();
  112. var input = [{_id: 0, a: 1}];
  113. cwc._cursor = new Cursor( input );
  114. var cds = new CursorDocumentSource(cwc);
  115. var pds = createProject();
  116. pds.setSource(cds);
  117. pds.getNext(function(err, actual) {
  118. assert.equal(1, actual.a);
  119. });
  120. },
  121. "The a and c.d fields are included but the b field is not": function testFullProject1(next) {
  122. var cwc = new CursorDocumentSource.CursorWithContext();
  123. var input = [{
  124. _id: 0,
  125. a: 1,
  126. b: 1,
  127. c: {
  128. d: 1
  129. }
  130. }];
  131. cwc._cursor = new Cursor(input);
  132. var cds = new CursorDocumentSource(cwc);
  133. var pds = createProject({
  134. a: true,
  135. c: {
  136. d: true
  137. }
  138. }),
  139. expected = {a:1, c:{ d: 1 }};
  140. pds.setSource(cds);
  141. pds.getNext(function(err,val) {
  142. assert.deepEqual(expected, val);
  143. next();
  144. });
  145. },
  146. "Two documents": function testTwoDocumentsProject(next) {
  147. var cwc = new CursorDocumentSource.CursorWithContext();
  148. var input = [{
  149. a: 1,
  150. b: 2
  151. }, {
  152. a: 3,
  153. b: 4
  154. }],
  155. expected = [
  156. {a:1},
  157. {a:3},
  158. DocumentSource.EOF
  159. ];
  160. cwc._cursor = new Cursor(input);
  161. var cds = new CursorDocumentSource(cwc);
  162. var pds = createProject({
  163. a: true,
  164. c: {
  165. d: true
  166. }
  167. });
  168. pds.setSource(cds);
  169. async.series([
  170. pds.getNext.bind(pds),
  171. pds.getNext.bind(pds),
  172. pds.getNext.bind(pds),
  173. ],
  174. function(err,res) {
  175. assert.deepEqual(expected, res);
  176. next();
  177. }
  178. );
  179. }
  180. },
  181. "#optimize()": {
  182. "Optimize the projection": function optimizeProject() {
  183. var pds = createProject({
  184. a: {
  185. $and: [true]
  186. }
  187. });
  188. pds.optimize();
  189. checkJsonRepresentation(pds, {
  190. $project: {
  191. a: {
  192. $const: true
  193. }
  194. }
  195. });
  196. }
  197. },
  198. "#createFromJson()": {
  199. "should error if called with non-object": function testNonObjectPassed() {
  200. //String as arg
  201. assert.throws(function() {
  202. var pds = createProject("not an object");
  203. });
  204. //Date as arg
  205. assert.throws(function() {
  206. var pds = createProject(new Date());
  207. });
  208. //Array as arg
  209. assert.throws(function() {
  210. var pds = createProject([]);
  211. });
  212. //Empty args
  213. assert.throws(function() {
  214. var pds = ProjectDocumentSource.createFromJson();
  215. });
  216. //Top level operator
  217. assert.throws(function() {
  218. var pds = createProject({
  219. $add: []
  220. });
  221. });
  222. //Invalid spec
  223. assert.throws(function() {
  224. var pds = createProject({
  225. a: {
  226. $invalidOperator: 1
  227. }
  228. });
  229. });
  230. }
  231. },
  232. "#getDependencies()": {
  233. "should properly detect dependencies in project": function testGetDependencies() {
  234. var cwc = new CursorDocumentSource.CursorWithContext();
  235. var input = {
  236. a: true,
  237. x: '$b',
  238. y: {
  239. $and: ['$c', '$d']
  240. }
  241. };
  242. var pds = createProject(input);
  243. var dependencies = {};
  244. assert.equal(DocumentSource.GetDepsReturn.EXHAUSTIVE, pds.getDependencies(dependencies));
  245. assert.equal(5, Object.keys(dependencies).length);
  246. assert.ok(dependencies._id);
  247. assert.ok(dependencies.a);
  248. assert.ok(dependencies.b);
  249. assert.ok(dependencies.c);
  250. assert.ok(dependencies.d);
  251. }
  252. }
  253. }
  254. };
  255. if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).grep(process.env.MOCHA_GREP || '').run(process.exit);