SkipDocumentSource.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. "use strict";
  2. var async = require("async"),
  3. DocumentSource = require("./DocumentSource");
  4. /**
  5. * A document source skipper.
  6. *
  7. * @class SkipDocumentSource
  8. * @namespace mungedb-aggregate.pipeline.documentSources
  9. * @module mungedb-aggregate
  10. * @constructor
  11. * @param [ctx] {ExpressionContext}
  12. **/
  13. var SkipDocumentSource = module.exports = function SkipDocumentSource(ctx) {
  14. if (arguments.length > 1) {
  15. throw new Error("Up to one argument expected.");
  16. }
  17. base.call(this, ctx);
  18. this.skip = 0;
  19. this.count = 0;
  20. this.needToSkip = true;
  21. }, klass = SkipDocumentSource, base = require("./DocumentSource"), proto = klass.prototype = Object.create(base.prototype, {constructor: {value: klass}}); //jshint ignore:line
  22. klass.skipName = "$skip";
  23. /**
  24. * Return the source name.
  25. *
  26. * @returns {string}
  27. */
  28. proto.getSourceName = function getSourceName() {
  29. return klass.skipName;
  30. };
  31. /**
  32. * Coalesce skips together.
  33. *
  34. * @param nextSource
  35. * @returns {boolean}
  36. */
  37. proto.coalesce = function coalesce(nextSource) {
  38. var nextSkip = nextSource.constructor === SkipDocumentSource ? nextSource : null;
  39. // If it's not another $skip, we can't coalesce.
  40. if (!nextSkip) {
  41. return false;
  42. }
  43. // We need to skip over the sum of the two consecutive $skips.
  44. this.skip += nextSkip.skip;
  45. return true;
  46. };
  47. /**
  48. * Returns the next Documnet if there is one or null if at EOF
  49. * @method getNext
  50. */
  51. proto.getNext = function getNext() {
  52. if (this.expCtx && this.expCtx.checkForInterrupt) this.expCtx.checkForInterrupt();
  53. if (this.needToSkip) {
  54. this.needToSkip = false;
  55. for (var i = 0; i < this._skip; i++) {
  56. if (!this.source.getNext())
  57. return null;
  58. }
  59. }
  60. return this.source.getNext();
  61. };
  62. /**
  63. * Serialize the source.
  64. *
  65. * @param explain
  66. * @returns {{}}
  67. */
  68. proto.serialize = function serialize(explain) {
  69. var out = {};
  70. out[this.getSourceName()] = this.skip;
  71. return out;
  72. };
  73. /**
  74. * Get skip value.
  75. *
  76. * @returns {number}
  77. */
  78. proto.getSkip = function getSkip() {
  79. return this.skip;
  80. };
  81. /**
  82. * Set skip value.
  83. *
  84. * @param newSkip
  85. */
  86. proto.setSkip = function setSkip(newSkip) {
  87. this.skip = newSkip;
  88. };
  89. /**
  90. * Create a new SkipDocumentSource.
  91. *
  92. * @param expCtx
  93. * @returns {SkipDocumentSource}
  94. */
  95. klass.create = function create(expCtx) {
  96. return new SkipDocumentSource(expCtx);
  97. };
  98. /**
  99. * Creates a new SkipDocumentSource with the input number as the skip.
  100. *
  101. * @param {Number} JsonElement this thing is *called* JSON, but it expects a number.
  102. **/
  103. klass.createFromJson = function createFromJson(jsonElement, ctx) {
  104. if (typeof jsonElement !== "number") {
  105. throw new Error("code 15972; the value to skip must be a number");
  106. }
  107. var nextSkip = new SkipDocumentSource(ctx);
  108. nextSkip.skip = jsonElement;
  109. if (nextSkip.skip < 0 || isNaN(nextSkip.skip)) {
  110. throw new Error("code 15956; the number to skip cannot be negative");
  111. }
  112. return nextSkip;
  113. };
  114. // SplittableDocumentSource implementation.
  115. klass.isSplittableDocumentSource = true;
  116. /**
  117. * Get dependencies.
  118. *
  119. * @param deps
  120. * @returns {number}
  121. */
  122. proto.getDependencies = function getDependencies(deps) {
  123. return DocumentSource.GetDepsReturn.SEE_NEXT;
  124. };
  125. /**
  126. * Get shard source.
  127. *
  128. * @returns {null}
  129. */
  130. proto.getShardSource = function getShardSource() {
  131. return null;
  132. };
  133. /**
  134. * Get router source.
  135. *
  136. * @returns {SkipDocumentSource}
  137. */
  138. proto.getRouterSource = function getRouterSource() {
  139. return this;
  140. };