/** * Copyright (C) 2011 10gen 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. */ #include "mongo/platform/basic.h" #include "mongo/db/pipeline/document_source.h" #include "mongo/db/pipeline/expression_context.h" #include "mongo/db/pipeline/value.h" #include "mongo/util/string_map.h" namespace mongo { using Parser = DocumentSource::Parser; using boost::intrusive_ptr; using std::string; using std::vector; DocumentSource::DocumentSource(const intrusive_ptr& pCtx) : pSource(NULL), pExpCtx(pCtx) {} namespace { // Used to keep track of which DocumentSources are registered under which name. static StringMap parserMap; } // namespace void DocumentSource::registerParser(string name, Parser parser) { auto it = parserMap.find(name); massert(28707, str::stream() << "Duplicate document source (" << name << ") registered.", it == parserMap.end()); parserMap[name] = parser; } vector> DocumentSource::parse( const intrusive_ptr expCtx, BSONObj stageObj) { uassert(16435, "A pipeline stage specification object must contain exactly one field.", stageObj.nFields() == 1); BSONElement stageSpec = stageObj.firstElement(); auto stageName = stageSpec.fieldNameStringData(); // Get the registered parser and call that. auto it = parserMap.find(stageName); uassert(16436, str::stream() << "Unrecognized pipeline stage name: '" << stageName << "'", it != parserMap.end()); return it->second(stageSpec, expCtx); } const char* DocumentSource::getSourceName() const { static const char unknown[] = "[UNKNOWN]"; return unknown; } void DocumentSource::setSource(DocumentSource* pTheSource) { verify(!isValidInitialSource()); pSource = pTheSource; } intrusive_ptr DocumentSource::optimize() { return this; } void DocumentSource::dispose() { if (pSource) { pSource->dispose(); } } void DocumentSource::serializeToArray(vector& array, bool explain) const { Value entry = serialize(explain); if (!entry.missing()) { array.push_back(entry); } } BSONObjSet DocumentSource::allPrefixes(BSONObj obj) { BSONObjSet out; BSONObj last = {}; for (auto&& field : obj) { BSONObjBuilder builder(last.objsize() + field.size()); builder.appendElements(last); builder.append(field); last = builder.obj(); out.insert(last); } return out; } BSONObjSet DocumentSource::truncateSortSet(const BSONObjSet& sorts, const std::set& fields) { BSONObjSet out; for (auto&& sort : sorts) { BSONObjBuilder outputSort; for (auto&& key : sort) { auto keyName = key.fieldNameStringData(); bool shouldAppend = true; for (auto&& field : fields) { if (keyName == field || keyName.startsWith(field + '.')) { shouldAppend = false; break; } } if (!shouldAppend) { break; } outputSort.append(key); } BSONObj outSortObj = outputSort.obj(); if (!outSortObj.isEmpty()) { out.insert(outSortObj); } } return out; } }