DocumentSource.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. "use strict";
  2. /**
  3. * A base class for all document sources
  4. * @class DocumentSource
  5. * @namespace mungedb-aggregate.pipeline.documentSources
  6. * @module mungedb-aggregate
  7. * @constructor
  8. * @param expCtx {ExpressionContext}
  9. **/
  10. var DocumentSource = module.exports = function DocumentSource(expCtx){
  11. if(arguments.length !== 1) throw new Error("one arg expected");
  12. /*
  13. * Most DocumentSources have an underlying source they get their data
  14. * from. This is a convenience for them.
  15. * The default implementation of setSource() sets this; if you don't
  16. * need a source, override that to verify(). The default is to
  17. * verify() if this has already been set.
  18. */
  19. this.source = null;
  20. /*
  21. * The zero-based user-specified pipeline step. Used for diagnostics.
  22. * Will be set to -1 for artificial pipeline steps that were not part
  23. * of the original user specification.
  24. */
  25. this.step = -1;
  26. this.expCtx = expCtx || {};
  27. /*
  28. * for explain: # of rows returned by this source
  29. * This is *not* unsigned so it can be passed to JSONObjBuilder.append().
  30. */
  31. this.nRowsOut = 0;
  32. }, klass = DocumentSource, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  33. /*
  34. class DocumentSource :
  35. public IntrusiveCounterUnsigned,
  36. public StringWriter {
  37. public:
  38. virtual ~DocumentSource();
  39. // virtuals from StringWriter
  40. virtual void writeString(stringstream &ss) const;
  41. */
  42. /**
  43. * Set the step for a user-specified pipeline step.
  44. * @method setPipelineStep
  45. * @param {Number} step number 0 to n.
  46. **/
  47. proto.setPipelineStep = function setPipelineStep(step) {
  48. this.step = step;
  49. };
  50. /**
  51. * Get the user-specified pipeline step.
  52. * @method getPipelineStep
  53. * @returns {Number} step
  54. **/
  55. proto.getPipelineStep = function getPipelineStep() {
  56. return this.step;
  57. };
  58. /**
  59. * Is the source at EOF?
  60. * @method eof
  61. **/
  62. proto.eof = function eof() {
  63. throw new Error("not implemented");
  64. };
  65. /**
  66. * Advance the state of the DocumentSource so that it will return the next Document.
  67. * The default implementation returns false, after checking for interrupts.
  68. * Derived classes can call the default implementation in their own implementations in order to check for interrupts.
  69. *
  70. * @method advance
  71. * @returns {Boolean} whether there is another document to fetch, i.e., whether or not getCurrent() will succeed. This default implementation always returns false.
  72. **/
  73. proto.advance = function advance() {
  74. //pExpCtx->checkForInterrupt(); // might not return
  75. return false;
  76. };
  77. /**
  78. * some implementations do the equivalent of verify(!eof()) so check eof() first
  79. * @method getCurrent
  80. * @returns {Document} the current Document without advancing
  81. **/
  82. proto.getCurrent = function getCurrent() {
  83. throw new Error("not implemented");
  84. };
  85. /**
  86. * Inform the source that it is no longer needed and may release its resources. After
  87. * dispose() is called the source must still be able to handle iteration requests, but may
  88. * become eof().
  89. * NOTE: For proper mutex yielding, dispose() must be called on any DocumentSource that will
  90. * not be advanced until eof(), see SERVER-6123.
  91. *
  92. * @method dispose
  93. **/
  94. proto.dispose = function dispose() {
  95. if ( this.source ) {
  96. // This is required for the DocumentSourceCursor to release its read lock, see
  97. // SERVER-6123.
  98. this.source.dispose();
  99. }
  100. };
  101. /**
  102. * Get the source's name.
  103. * @method getSourceName
  104. * @returns {String} the string name of the source as a constant string; this is static, and there's no need to worry about adopting it
  105. **/
  106. proto.getSourceName = function getSourceName() {
  107. return "[UNKNOWN]";
  108. };
  109. /**
  110. * Set the underlying source this source should use to get Documents
  111. * from.
  112. * It is an error to set the source more than once. This is to
  113. * prevent changing sources once the original source has been started;
  114. * this could break the state maintained by the DocumentSource.
  115. * This pointer is not reference counted because that has led to
  116. * some circular references. As a result, this doesn't keep
  117. * sources alive, and is only intended to be used temporarily for
  118. * the lifetime of a Pipeline::run().
  119. *
  120. * @method setSource
  121. * @param {DocumentSource} source the underlying source to use
  122. **/
  123. proto.setSource = function setSource(theSource, callback) {
  124. if (this.source) throw new Error("It is an error to set the source more than once");
  125. this.source = theSource;
  126. if (callback) return setTimeout(callback, 0);
  127. };
  128. /**
  129. * Attempt to coalesce this DocumentSource with its successor in the
  130. * document processing pipeline. If successful, the successor
  131. * DocumentSource should be removed from the pipeline and discarded.
  132. * If successful, this operation can be applied repeatedly, in an
  133. * attempt to coalesce several sources together.
  134. * The default implementation is to do nothing, and return false.
  135. *
  136. * @method coalesce
  137. * @param {DocumentSource} nextSource the next source in the document processing chain.
  138. * @returns {Boolean} whether or not the attempt to coalesce was successful or not; if the attempt was not successful, nothing has been changed
  139. **/
  140. proto.coalesce = function coalesce(nextSource) {
  141. return false;
  142. };
  143. /**
  144. * Optimize the pipeline operation, if possible. This is a local
  145. * optimization that only looks within this DocumentSource. For best
  146. * results, first coalesce compatible sources using coalesce().
  147. * This is intended for any operations that include expressions, and
  148. * provides a hook for those to optimize those operations.
  149. * The default implementation is to do nothing.
  150. *
  151. * @method optimize
  152. **/
  153. proto.optimize = function optimize() {
  154. };
  155. klass.GetDepsReturn = {
  156. NOT_SUPPORTED: "NOT_SUPPORTED", // This means the set should be ignored
  157. EXHAUSTIVE: "EXHAUSTIVE", // This means that everything needed should be in the set
  158. SEE_NEXT: "SEE_NEXT" // Add the next Source's deps to the set
  159. };
  160. /**
  161. * Get the fields this operation needs to do its job.
  162. * Deps should be in "a.b.c" notation
  163. *
  164. * @method getDependencies
  165. * @param {Object} deps set (unique array) of strings
  166. * @returns DocumentSource.GetDepsReturn
  167. **/
  168. proto.getDependencies = function getDependencies(deps) {
  169. return klass.GetDepsReturn.NOT_SUPPORTED;
  170. };
  171. /**
  172. * This takes dependencies from getDependencies and
  173. * returns a projection that includes all of them
  174. *
  175. * @method depsToProjection
  176. * @param {Object} deps set (unique array) of strings
  177. * @returns {Object} JSONObj
  178. **/
  179. klass.depsToProjection = function depsToProjection(deps) {
  180. var bb = {};
  181. if (deps._id === undefined)
  182. bb._id = 0;
  183. var last = "";
  184. Object.keys(deps).sort().forEach(function(it){
  185. if (last !== "" && it.slice(0, last.length) === last){
  186. // we are including a parent of *it so we don't need to
  187. // include this field explicitly. In fact, due to
  188. // SERVER-6527 if we included this field, the parent
  189. // wouldn't be fully included.
  190. return;
  191. }
  192. last = it + ".";
  193. bb[it] = 1;
  194. });
  195. return bb;
  196. };
  197. /**
  198. * Add the DocumentSource to the array builder.
  199. * The default implementation calls sourceToJson() in order to
  200. * convert the inner part of the object which will be added to the
  201. * array being built here.
  202. *
  203. * @method addToJsonArray
  204. * @param {Array} pBuilder JSONArrayBuilder: the array builder to add the operation to.
  205. * @param {Boolean} explain create explain output
  206. * @returns {Object}
  207. **/
  208. proto.addToJsonArray = function addToJsonArray(pBuilder, explain) {
  209. pBuilder.push(this.sourceToJson({}, explain));
  210. };
  211. /**
  212. * Create an object that represents the document source. The object
  213. * will have a single field whose name is the source's name. This
  214. * will be used by the default implementation of addToJsonArray()
  215. * to add this object to a pipeline being represented in JSON.
  216. *
  217. * @method sourceToJson
  218. * @param {Object} pBuilder JSONObjBuilder: a blank object builder to write to
  219. * @param {Boolean} explain create explain output
  220. **/
  221. proto.sourceToJson = function sourceToJson(pBuilder, explain) {
  222. throw new Error("not implemented");
  223. };
  224. /**
  225. * Convert the DocumentSource instance to it's JSON Object representation; Used by the standard JSON.stringify() function
  226. * @method toJSON
  227. * @return {String} a JSON-encoded String that represents the DocumentSource
  228. **/
  229. proto.toJSON = function toJSON(){
  230. var obj = {};
  231. this.sourceToJson(obj);
  232. return obj;
  233. };