diff options
Diffstat (limited to 'src/mongo/db/pipeline/parsed_aggregation_projection.h')
-rw-r--r-- | src/mongo/db/pipeline/parsed_aggregation_projection.h | 91 |
1 files changed, 79 insertions, 12 deletions
diff --git a/src/mongo/db/pipeline/parsed_aggregation_projection.h b/src/mongo/db/pipeline/parsed_aggregation_projection.h index a3420fdb954..6e8d9100845 100644 --- a/src/mongo/db/pipeline/parsed_aggregation_projection.h +++ b/src/mongo/db/pipeline/parsed_aggregation_projection.h @@ -28,26 +28,89 @@ #pragma once +#include "mongo/platform/basic.h" + #include <boost/intrusive_ptr.hpp> #include <memory> +#include "mongo/bson/bsonelement.h" +#include "mongo/db/pipeline/document_source.h" +#include "mongo/db/pipeline/field_path.h" + namespace mongo { class BSONObj; class Document; -struct DepsTracker; struct ExpressionContext; namespace parsed_aggregation_projection { -enum class ProjectionType { kExclusion, kInclusion }; +enum class ProjectionType { kExclusion, kInclusion, kComputed }; + +/** + * This class ensures that the specification was valid: that none of the paths specified conflict + * with one another, that there is at least one field, etc. Here "projection" includes both + * $project specifications and $addFields specifications. + */ +class ProjectionSpecValidator { +public: + /** + * Returns a Status: either a Status::OK() if the specification is valid for a projection, or a + * non-OK Status, error number, and message with why not. + */ + static Status validate(const BSONObj& spec); + +private: + ProjectionSpecValidator(const BSONObj& spec) : _rawObj(spec) {} + + /** + * Uses '_seenPaths' to see if 'path' conflicts with any paths that have already been specified. + * + * For example, a user is not allowed to specify {'a': 1, 'a.b': 1}, or some similar conflicting + * paths. + */ + Status ensurePathDoesNotConflictOrThrow(StringData path); + + /** + * Returns the relevant error if an invalid projection specification is detected. + */ + Status validate(); + + /** + * Parses a single BSONElement. 'pathToElem' should include the field name of 'elem'. + * + * Delegates to parseSubObject() if 'elem' is an object. Otherwise adds the full path to 'elem' + * to '_seenPaths'. + * + * Calls ensurePathDoesNotConflictOrThrow with the path to this element, which sets the _status + * appropriately for conflicting path specifications. + */ + Status parseElement(const BSONElement& elem, const FieldPath& pathToElem); + + /** + * Traverses 'thisLevelSpec', parsing each element in turn. + * + * Sets _status appropriately if any paths conflict with each other or existing paths, + * 'thisLevelSpec' contains a dotted path, or if 'thisLevelSpec' represents an invalid + * expression. + */ + Status parseNestedObject(const BSONObj& thisLevelSpec, const FieldPath& prefix); + + // The original object. Used to generate more helpful error messages. + const BSONObj& _rawObj; + + // Tracks which paths we've seen to ensure no two paths conflict with each other. + // Can be a vector since we iterate through it. + std::vector<std::string> _seenPaths; +}; /** - * A ParsedAggregationProjection is responsible for parsing and executing a projection. It + * A ParsedAggregationProjection is responsible for parsing and executing a $project. It * represents either an inclusion or exclusion projection. This is the common interface between the * two types of projections. */ -class ParsedAggregationProjection { +class ParsedAggregationProjection + : public DocumentSourceSingleDocumentTransformation::TransformerInterface { public: /** * Main entry point for a ParsedAggregationProjection. @@ -72,11 +135,6 @@ public: virtual void parse(const BSONObj& spec) = 0; /** - * Serialize this projection. - */ - virtual Document serialize(bool explain = false) const = 0; - - /** * Optimize any expressions contained within this projection. */ virtual void optimize() {} @@ -89,15 +147,24 @@ public: /** * Add any dependencies needed by this projection or any sub-expressions to 'deps'. */ - virtual void addDependencies(DepsTracker* deps) const {} + virtual DocumentSource::GetDepsReturn addDependencies(DepsTracker* deps) const { + return DocumentSource::NOT_SUPPORTED; + } /** - * Apply the projection to 'input'. + * Apply the projection transformation. */ - virtual Document applyProjection(Document input) const = 0; + Document applyTransformation(Document input) { + return applyProjection(input); + } protected: ParsedAggregationProjection() = default; + + /** + * Apply the projection to 'input'. + */ + virtual Document applyProjection(Document input) const = 0; }; } // namespace parsed_aggregation_projection } // namespace mongo |