Pipeline.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. "use strict";
  2. var assert = require("assert"),
  3. Pipeline = require("../../../lib/pipeline/Pipeline"),
  4. FieldPath = require("../../../lib/pipeline/FieldPath"),
  5. DocumentSource = require('../../../lib/pipeline/documentSources/DocumentSource');
  6. module.exports = {
  7. "Pipeline": {
  8. before: function(){
  9. Pipeline.stageDesc.$test = (function(){
  10. var klass = function TestDocumentSource(options, ctx){
  11. base.call(this, ctx);
  12. this.shouldCoalesce = options.coalesce;
  13. this.coalesceWasCalled = false;
  14. this.optimizeWasCalled = false;
  15. this.works = options.works === false ? false : true; // don't judge
  16. this.current = 5;
  17. }, TestDocumentSource = klass, base = DocumentSource, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  18. proto.coalesce = function(){
  19. this.coalesceWasCalled = true;
  20. var c = this.shouldCoalesce;//only coalesce with the first thing we find
  21. this.shouldCoalesce = false;
  22. return c;
  23. };
  24. proto.optimize = function(){
  25. this.optimizeWasCalled = true;
  26. };
  27. proto.getNext = function(callback){
  28. var answer = this.current > 0 ? {val:this.current--} : DocumentSource.EOF,
  29. err = null;
  30. if (!this.works)
  31. err = new Error("doesn't work"), answer = undefined;
  32. if(callback) {
  33. return callback(err, answer);
  34. } else {
  35. return answer || err;
  36. }
  37. };
  38. klass.createFromJson = function(options, ctx){
  39. return new TestDocumentSource(options, ctx);
  40. };
  41. return klass;
  42. })().createFromJson;
  43. },
  44. "parseCommand": {
  45. "should throw Error if given non-objects in the array": function () {
  46. assert.throws(function(){
  47. Pipeline.parseCommand({pipeline:[5]});
  48. });
  49. },
  50. "should throw Error if given objects with more / less than one field": function () {
  51. assert.throws(function(){
  52. Pipeline.parseCommand({pipeline:[{}]});
  53. Pipeline.parseCommand({pipeline:[{a:1,b:2}]});
  54. });
  55. },
  56. "should throw Error on unknown document sources": function () {
  57. assert.throws(function(){
  58. Pipeline.parseCommand({pipeline:[{$foo:"$sdfdf"}]});
  59. });
  60. },
  61. "should swap $match and $sort if the $match immediately follows the $sort": function () {
  62. var p = Pipeline.parseCommand({pipeline:[{$sort:{"xyz":1}}, {$match:{}}]});
  63. assert.equal(p.sources[0].constructor.matchName, "$match");
  64. assert.equal(p.sources[1].constructor.sortName, "$sort");
  65. },
  66. "should attempt to coalesce all sources": function () {
  67. var p = Pipeline.parseCommand({pipeline:[{$test:{coalesce:false}}, {$test:{coalesce:true}}, {$test:{coalesce:false}}, {$test:{coalesce:false}}]});
  68. assert.equal(p.sources.length, 3);
  69. p.sources.slice(0,-1).forEach(function(source){
  70. assert.equal(source.coalesceWasCalled, true);
  71. });
  72. assert.equal(p.sources[p.sources.length -1].coalesceWasCalled, false);
  73. },
  74. "should optimize all sources": function () {
  75. var p = Pipeline.parseCommand({pipeline:[{$test:{coalesce:false}}, {$test:{coalesce:false}}]});
  76. p.sources.forEach(function(source){
  77. assert.equal(source.optimizeWasCalled, true);
  78. });
  79. }
  80. },
  81. "#stitch": {
  82. "should set the parent source for all sources in the pipeline except the first one": function () {
  83. var p = Pipeline.parseCommand({pipeline:[{$test:{coalesce:false}}, {$test:{coalesce:false}}, {$test:{coalesce:false}}]});
  84. p.stitch();
  85. assert.equal(p.sources[1].source, p.sources[0]);
  86. }
  87. },
  88. "#_runSync": {
  89. "should iterate through sources and return resultant array": function () {
  90. var p = Pipeline.parseCommand({pipeline:[{$test:{coalesce:false}}, {$test:{coalesce:false}}, {$test:{coalesce:false}}]}),
  91. results = p.run(function(err, results) {
  92. assert.deepEqual(results.result, [ { val: 5 }, { val: 4 }, { val: 3 }, { val: 2 }, { val: 1 } ]);
  93. });
  94. },
  95. "should call callback with errors from pipeline components": function (next) {
  96. var p = Pipeline.parseCommand({pipeline:[{$test:{coalesce:false}}, {$test:{coalesce:false}}, {$test:{coalesce:false,works:false}}]});
  97. p.run(function(err, results){
  98. assert(err instanceof Error);
  99. return next();
  100. });
  101. }
  102. },
  103. "#_runAsync": {
  104. "should iterate through sources and return resultant array asynchronously": function () {
  105. var p = Pipeline.parseCommand({pipeline:[{$test:{coalesce:false}}, {$test:{coalesce:false}}, {$test:{coalesce:false}}]}),
  106. results = p.run(function(err, results) {
  107. assert.deepEqual(results.result, [ { val: 5 }, { val: 4 }, { val: 3 }, { val: 2 }, { val: 1 } ]);
  108. });
  109. }
  110. },
  111. "#addInitialSource": {
  112. "should put the given source at the beginning of the pipeline": function () {
  113. var p = Pipeline.parseCommand({pipeline:[{$test:{coalesce:false}}, {$test:{coalesce:false}}, {$test:{coalesce:false}}]}),
  114. initialSource = Pipeline.stageDesc.$test({coalesce:false});
  115. p.addInitialSource(initialSource);
  116. assert.equal(initialSource, p.sources[0]);
  117. },
  118. "should be able to addInitialSource then stitch": function () {
  119. var p = Pipeline.parseCommand({pipeline:[{$test:{coalesce:false}}, {$test:{coalesce:false}}, {$test:{coalesce:false}}]}),
  120. initialSource = Pipeline.stageDesc.$test({coalesce:false});
  121. p.addInitialSource(initialSource);
  122. p.stitch();
  123. assert.equal(p.sources[1].source, p.sources[0]);
  124. }
  125. }
  126. }
  127. };
  128. if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).grep(process.env.MOCHA_GREP || '').run(process.exit);