ProjectDocumentSource_test.js 6.7 KB

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