Pipeline.js 4.6 KB

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