// expression.h
/**
* Copyright (C) 2013 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.
*/
#pragma once
#include
#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/db/matcher/matchable.h"
#include "mongo/db/matcher/match_details.h"
namespace mongo {
class TreeMatchExpression;
class MatchExpression {
MONGO_DISALLOW_COPYING( MatchExpression );
public:
enum MatchType {
// tree types
AND, OR, NOR, NOT,
// array types
ALL, ELEM_MATCH_OBJECT, ELEM_MATCH_VALUE, SIZE,
// leaf types
LTE, LT, EQ, GT, GTE, REGEX, MOD, EXISTS, MATCH_IN, NIN,
// special types
TYPE_OPERATOR, GEO, WHERE,
// things that maybe shouldn't even be nodes
ATOMIC, ALWAYS_FALSE,
// Things that we parse but cannot be answered without an index.
GEO_NEAR, TEXT,
// Expressions that are only created internally
INTERNAL_GEO_S2_KEYCHECK
};
MatchExpression( MatchType type );
virtual ~MatchExpression(){}
//
// Structural/AST information
//
/**
* What type is the node? See MatchType above.
*/
MatchType matchType() const { return _matchType; }
/**
* How many children does the node have? Most nodes are leaves so the default impl. is for
* a leaf.
*/
virtual size_t numChildren() const { return 0; }
/**
* Get the i-th child.
*/
virtual MatchExpression* getChild( size_t i ) const { return NULL; }
/**
* Get all the children of a node
*/
virtual std::vector* getChildVector() { return NULL; }
/**
* Get the path of the leaf. Returns StringData() if there is no path (node is logical).
*/
virtual const StringData path() const { return StringData(); }
/**
* Notes on structure:
* isLogical, isArray, and isLeaf define three partitions of all possible operators.
*
* isLogical can have children and its children can be arbitrary operators.
*
* isArray can have children and its children are predicates over one field.
*
* isLeaf is a predicate over one field.
*/
/**
* Is this node a logical operator? All of these inherit from ListOfMatchExpression.
* AND, OR, NOT, NOR.
*/
bool isLogical() const {
return AND == _matchType || OR == _matchType || NOT == _matchType || NOR == _matchType;
}
/**
* Is this node an array operator? Array operators have multiple clauses but operate on one
* field.
*
* ALL (AllElemMatchOp)
* ELEM_MATCH_VALUE, ELEM_MATCH_OBJECT, SIZE (ArrayMatchingMatchExpression)
*/
bool isArray() const {
return SIZE == _matchType || ALL == _matchType || ELEM_MATCH_VALUE == _matchType
|| ELEM_MATCH_OBJECT == _matchType;
}
/**
* Not-internal nodes, predicates over one field. Almost all of these inherit from
* LeafMatchExpression.
*
* Exceptions: WHERE, which doesn't have a field.
* TYPE_OPERATOR, which inherits from MatchExpression due to unique array
* semantics.
*/
bool isLeaf() const {
return !isArray() && !isLogical();
}
// XXX: document
virtual MatchExpression* shallowClone() const = 0;
// XXX document
virtual bool equivalent( const MatchExpression* other ) const = 0;
//
// Determine if a document satisfies the tree-predicate.
//
virtual bool matches( const MatchableDocument* doc, MatchDetails* details = 0 ) const = 0;
virtual bool matchesBSON( const BSONObj& doc, MatchDetails* details = 0 ) const;
/**
* Determines if the element satisfies the tree-predicate.
* Not valid for all expressions (e.g. $where); in those cases, returns false.
*/
virtual bool matchesSingleElement( const BSONElement& e ) const = 0;
//
// Tagging mechanism: Hang data off of the tree for retrieval later.
//
class TagData {
public:
virtual ~TagData() { }
virtual void debugString(StringBuilder* builder) const = 0;
virtual TagData* clone() const = 0;
};
/**
* Takes ownership
*/
void setTag(TagData* data) { _tagData.reset(data); }
TagData* getTag() const { return _tagData.get(); }
virtual void resetTag() {
setTag(NULL);
for (size_t i = 0; i < numChildren(); ++i) {
getChild(i)->resetTag();
}
}
//
// Debug information
//
virtual string toString() const;
virtual void debugString( StringBuilder& debug, int level = 0 ) const = 0;
protected:
void _debugAddSpace( StringBuilder& debug, int level ) const;
private:
MatchType _matchType;
boost::scoped_ptr _tagData;
};
/**
* this isn't really an expression, but a hint to other things
* not sure where to put it in the end
*/
class AtomicMatchExpression : public MatchExpression {
public:
AtomicMatchExpression() : MatchExpression( ATOMIC ){}
virtual bool matches( const MatchableDocument* doc, MatchDetails* details = 0 ) const {
return true;
}
virtual bool matchesSingleElement( const BSONElement& e ) const {
return true;
}
virtual MatchExpression* shallowClone() const {
return new AtomicMatchExpression();
}
virtual void debugString( StringBuilder& debug, int level = 0 ) const;
virtual bool equivalent( const MatchExpression* other ) const {
return other->matchType() == ATOMIC;
}
};
class FalseMatchExpression : public MatchExpression {
public:
FalseMatchExpression() : MatchExpression( ALWAYS_FALSE ){}
virtual bool matches( const MatchableDocument* doc, MatchDetails* details = 0 ) const {
return false;
}
virtual bool matchesSingleElement( const BSONElement& e ) const {
return false;
}
virtual MatchExpression* shallowClone() const {
return new FalseMatchExpression();
}
virtual void debugString( StringBuilder& debug, int level = 0 ) const;
virtual bool equivalent( const MatchExpression* other ) const {
return other->matchType() == ALWAYS_FALSE;
}
};
}