ProjectDocumentSource.js 3.8 KB

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