summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/parsed_aggregation_projection.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/pipeline/parsed_aggregation_projection.h')
-rw-r--r--src/mongo/db/pipeline/parsed_aggregation_projection.h91
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