/** * Copyright (C) 2016 MongoDB, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #pragma once #include #include #include "mongo/db/pipeline/parsed_aggregation_projection.h" #include "mongo/stdx/unordered_map.h" #include "mongo/stdx/unordered_set.h" namespace mongo { class FieldPath; class Value; namespace parsed_aggregation_projection { /** * A node used to define the parsed structure of an exclusion projection. Each ExclusionNode * represents one 'level' of the parsed specification. The root ExclusionNode represents all top * level exclusions, with any child ExclusionNodes representing dotted or nested exclusions. */ class ExclusionNode { public: ExclusionNode(std::string pathToNode = ""); /** * Serialize this exclusion. */ Document serialize() const; /** * Mark this path to be excluded. 'path' is allowed to be dotted. */ void excludePath(FieldPath path); /** * Applies this tree of exclusions to the input document. */ Document applyProjection(const Document& input) const; /** * Creates the child if it doesn't already exist. 'field' is not allowed to be dotted. */ ExclusionNode* addOrGetChild(FieldPath field); void addModifiedPaths(std::set* modifiedPaths) const; private: // Helpers for addOrGetChild above. ExclusionNode* getChild(std::string field) const; ExclusionNode* addChild(std::string field); // Helper for applyProjection above. Value applyProjectionToValue(Value val) const; // Fields excluded at this level. stdx::unordered_set _excludedFields; std::string _pathToNode; stdx::unordered_map> _children; }; /** * A ParsedExclusionProjection represents a parsed form of the raw BSON specification. * * This class is mostly a wrapper around an ExclusionNode tree. It contains logic to parse a * specification object into the corresponding ExclusionNode tree, but defers most execution logic * to the underlying tree. */ class ParsedExclusionProjection : public ParsedAggregationProjection { public: ParsedExclusionProjection(const boost::intrusive_ptr& expCtx) : ParsedAggregationProjection(expCtx), _root(new ExclusionNode()) {} TransformerType getType() const final { return TransformerType::kExclusionProjection; } Document serialize(boost::optional explain) const final; /** * Parses the projection specification given by 'spec', populating internal data structures. */ void parse(const BSONObj& spec) final { parse(spec, _root.get(), 0); } /** * Exclude the fields specified. */ Document applyProjection(const Document& inputDoc) const final; DocumentSource::GetDepsReturn addDependencies(DepsTracker* deps) const final { return DocumentSource::SEE_NEXT; } DocumentSource::GetModPathsReturn getModifiedPaths() const final { std::set modifiedPaths; _root->addModifiedPaths(&modifiedPaths); return {DocumentSource::GetModPathsReturn::Type::kFiniteSet, std::move(modifiedPaths), {}}; } private: /** * Helper for parse() above. * * Traverses 'spec' and parses each field. Adds any excluded fields at this level to 'node', * and recurses on any sub-objects. */ void parse(const BSONObj& spec, ExclusionNode* node, size_t depth); // The ExclusionNode tree does most of the execution work once constructed. std::unique_ptr _root; }; } // namespace parsed_aggregation_projection } // namespace mongo