ProjectDocumentSource.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. "use strict";
  2. var DocumentSource = require('./DocumentSource');
  3. /**
  4. * A base class for filter document sources
  5. * @class ProjectDocumentSource
  6. * @namespace mungedb-aggregate.pipeline.documentSources
  7. * @module mungedb-aggregate
  8. * @constructor
  9. * @param [ctx] {ExpressionContext}
  10. **/
  11. var ProjectDocumentSource = module.exports = function ProjectDocumentSource(ctx){
  12. if (arguments.length > 1) throw new Error("up to one arg expected");
  13. base.call(this, ctx);
  14. this.OE = new ObjectExpression();
  15. this._raw = undefined;
  16. }, klass = ProjectDocumentSource, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  17. // DEPENDENCIES
  18. var Expression = require('../expressions/Expression'),
  19. ObjectExpression = require('../expressions/ObjectExpression'),
  20. Value = require('../Value'),
  21. Variables = require('../expressions/Variables'),
  22. VariablesIdGenerator = require('../expressions/VariablesIdGenerator'),
  23. VariablesParseState = require('../expressions/VariablesParseState');
  24. klass.projectName = "$project";
  25. /**
  26. * Returns the name of project
  27. * @return {string} the name of project
  28. **/
  29. proto.getSourceName = function getSourceName() {
  30. return klass.projectName;
  31. };
  32. proto.getNext = function getNext(callback) {
  33. if (!callback) throw new Error(this.getSourceName() + ' #getNext() requires callback');
  34. var self = this,
  35. out;
  36. this.source.getNext(function(err, input) {
  37. if (err)
  38. return callback(null, err);
  39. if (input === DocumentSource.EOF) {
  40. out = input;
  41. return callback(null, DocumentSource.EOF);
  42. }
  43. /* create the result document */
  44. out = {};
  45. /**
  46. * Use the ExpressionObject to create the base result.
  47. *
  48. * If we're excluding fields at the top level, leave out the _id if
  49. * it is found, because we took care of it above.
  50. **/
  51. self._variables.setRoot(input);
  52. self.OE.addToDocument(out, input, self._variables);
  53. self._variables.clearRoot();
  54. return callback(null, out);
  55. });
  56. return out;
  57. };
  58. /**
  59. * Returns the object that was used to construct the ProjectDocumentSource
  60. * @return {object} the object that was used to construct the ProjectDocumentSource
  61. **/
  62. proto.getRaw = function getRaw() {
  63. return this._raw;
  64. };
  65. proto.serialize = function serialize(explain) {
  66. var out = {};
  67. out[this.getSourceName()] = this.OE.serialize(explain);
  68. return out;
  69. };
  70. /**
  71. * Optimizes the internal ObjectExpression
  72. * @return
  73. **/
  74. proto.optimize = function optimize() {
  75. this.OE.optimize();
  76. };
  77. proto.toJSON = function toJSON(){
  78. var obj = {};
  79. this.sourceToJson(obj);
  80. return obj;
  81. };
  82. /**
  83. * Places a $project key inside the builder object with value of this.OE
  84. * @method sourceToJson
  85. * @param {builder} An object (was ported from BsonBuilder)
  86. * @return
  87. **/
  88. proto.sourceToJson = function sourceToJson(builder, explain) {
  89. var insides = this.OE.toJSON(true);
  90. builder[this.getSourceName()] = insides;
  91. };
  92. /**
  93. * Builds a new ProjectDocumentSource from an object
  94. * @method createFromJson
  95. * @return {ProjectDocmentSource} a ProjectDocumentSource instance
  96. **/
  97. klass.createFromJson = function(jsonElement, expCtx) {
  98. if (!(jsonElement instanceof Object) || jsonElement.constructor !== Object) throw new Error('Error 15969. Specification must be an object but was ' + typeof jsonElement);
  99. var objectContext = new Expression.ObjectCtx({
  100. isDocumentOk: true,
  101. isTopLevel: true,
  102. isInclusionOk: true
  103. });
  104. var project = new ProjectDocumentSource(expCtx),
  105. idGenerator = new VariablesIdGenerator(),
  106. vps = new VariablesParseState(idGenerator);
  107. project._raw = jsonElement;
  108. var parsed = Expression.parseObject(jsonElement, objectContext, vps);
  109. var exprObj = parsed;
  110. if (!exprObj instanceof ObjectExpression) throw new Error("16402, parseObject() returned wrong type of Expression");
  111. if (!exprObj.getFieldCount()) throw new Error("16403, $projection requires at least one output field");
  112. project.OE = exprObj;
  113. project._variables = new Variables(idGenerator.getIdCount());
  114. return project;
  115. };
  116. /**
  117. * Adds dependencies to the contained ObjectExpression
  118. * @param {deps} An object that is treated as a set of strings
  119. * @return A string that is part of the GetDepsReturn enum
  120. **/
  121. proto.getDependencies = function getDependencies(deps) {
  122. var path = [];
  123. this.OE.addDependencies(deps, path);
  124. return base.GetDepsReturn.EXHAUSTIVE;
  125. };