Skip to content

Commit

Permalink
SERVER-9820: Introduce Path and iterators such that all bson walking …
Browse files Browse the repository at this point in the history
…logic is one place
  • Loading branch information
erh committed May 30, 2013
1 parent a6d0550 commit 2962381
Show file tree
Hide file tree
Showing 16 changed files with 824 additions and 304 deletions.
11 changes: 9 additions & 2 deletions src/mongo/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -113,19 +113,27 @@ env.CppUnitTest('namespacestring_test', ['db/namespacestring_test.cpp'],
env.CppUnitTest('index_set_test', ['db/index_set_test.cpp'],
LIBDEPS=['bson','index_set'])

env.StaticLibrary('path',
['db/matcher/path.cpp',
'db/matcher/path_internal.cpp'],
LIBDEPS=['bson',
'$BUILD_DIR/mongo/db/common'])

env.CppUnitTest('path_test', ['db/matcher/path_test.cpp'],
LIBDEPS=['path'])


env.StaticLibrary('expressions',
['db/matcher/expression.cpp',
'db/matcher/expression_array.cpp',
'db/matcher/expression_internal.cpp',
'db/matcher/expression_leaf.cpp',
'db/matcher/expression_tree.cpp',
'db/matcher/expression_parser.cpp',
'db/matcher/expression_parser_tree.cpp',
'db/matcher/matchable.cpp',
'db/matcher/match_details.cpp'],
LIBDEPS=['bson',
'path',
'$BUILD_DIR/mongo/db/common',
'$BUILD_DIR/third_party/pcrecpp'
] )
Expand All @@ -139,7 +147,6 @@ env.StaticLibrary('expressions_where',
['db/matcher/expression_where.cpp'],
LIBDEPS=['expressions'] )


env.CppUnitTest('expression_test',
['db/matcher/expression_test.cpp',
'db/matcher/expression_leaf_test.cpp',
Expand Down
95 changes: 32 additions & 63 deletions src/mongo/db/matcher/expression_array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,63 +18,38 @@

#include "mongo/db/matcher/expression_array.h"

#include "mongo/bson/bsonobjiterator.h"
#include "mongo/db/field_ref.h"
#include "mongo/db/matcher/expression_internal.h"
#include "mongo/db/jsobj.h"
#include "mongo/util/log.h"

namespace mongo {

bool ArrayMatchingMatchExpression::matches( const MatchableDocument* doc, MatchDetails* details ) const {

FieldRef path;
path.parse(_path);

bool traversedArray = false;
size_t idxPath = 0;
BSONElement e = doc->getFieldDottedOrArray( path, &idxPath, &traversedArray );

string rest = path.dottedField( idxPath+1 );
bool restIsNumber = isAllDigits( rest );
Status ArrayMatchingMatchExpression::initPath( const StringData& path ) {
_path = path;
Status s = _elementPath.init( _path );
_elementPath.setTraverseLeafArray( false );
return s;
}

if ( rest.size() == 0 ) {
if ( e.type() == Array )
return matchesArray( e.Obj(), details );
return false;
}
bool ArrayMatchingMatchExpression::matches( const MatchableDocument* doc, MatchDetails* details ) const {

if ( e.type() != Array )
return false;
boost::scoped_ptr<ElementIterator> cursor( doc->getIterator( _elementPath ) );

BSONObjIterator i( e.Obj() );
while ( i.more() ) {
BSONElement x = i.next();
if ( ! x.isABSONObj() )
while ( cursor->more() ) {
ElementIterator::Element e = cursor->next();
if ( e.element().type() != Array )
continue;

if ( restIsNumber && rest == x.fieldName() ) {
if ( matchesArray( x.Obj(), NULL ) ) {
if ( details && details->needRecord() ) {
// trying to match crazy semantics??
details->setElemMatchKey( x.fieldName() );
}
return true;
}
}
bool amIRoot = e.arrayOffset().eoo();

BSONElement sub = x.Obj().getFieldDotted( rest );
if ( sub.type() != Array )
if ( !matchesArray( e.element().Obj(), amIRoot ? details : NULL ) )
continue;

if ( matchesArray( sub.Obj(), NULL ) ) {
if ( details && details->needRecord() ) {
// trying to match crazy semantics??
details->setElemMatchKey( x.fieldName() );
}
return true;
if ( !amIRoot && details && details->needRecord() && !e.arrayOffset().eoo() ) {
details->setElemMatchKey( e.arrayOffset().fieldName() );
}
return true;
}

return false;
}

Expand Down Expand Up @@ -108,13 +83,10 @@ namespace mongo {
// -------

Status ElemMatchObjectMatchExpression::init( const StringData& path, const MatchExpression* sub ) {
_path = path;
_sub.reset( sub );
return Status::OK();
return initPath( path );
}



bool ElemMatchObjectMatchExpression::matchesArray( const BSONObj& anArray, MatchDetails* details ) const {
BSONObjIterator i( anArray );
while ( i.more() ) {
Expand All @@ -133,7 +105,7 @@ namespace mongo {

void ElemMatchObjectMatchExpression::debugString( StringBuilder& debug, int level ) const {
_debugAddSpace( debug, level );
debug << _path << " $elemMatch\n";
debug << path() << " $elemMatch\n";
_sub->debugString( debug, level + 1 );
}

Expand All @@ -153,8 +125,7 @@ namespace mongo {
}

Status ElemMatchValueMatchExpression::init( const StringData& path ) {
_path = path;
return Status::OK();
return initPath( path );
}


Expand Down Expand Up @@ -188,7 +159,7 @@ namespace mongo {

void ElemMatchValueMatchExpression::debugString( StringBuilder& debug, int level ) const {
_debugAddSpace( debug, level );
debug << _path << " $elemMatch\n";
debug << path() << " $elemMatch\n";
for ( unsigned i = 0; i < _subs.size(); i++ ) {
_subs[i]->debugString( debug, level + 1 );
}
Expand All @@ -205,7 +176,9 @@ namespace mongo {

Status AllElemMatchOp::init( const StringData& path ) {
_path = path;
return Status::OK();
Status s = _elementPath.init( _path );
_elementPath.setTraverseLeafArray( false );
return s;
}

void AllElemMatchOp::add( const ArrayMatchingMatchExpression* expr ) {
Expand All @@ -214,16 +187,13 @@ namespace mongo {
}

bool AllElemMatchOp::matches( const MatchableDocument* doc, MatchDetails* details ) const {
BSONElementSet all;
doc->getFieldsDotted( _path, all, false );

for ( BSONElementSet::const_iterator i = all.begin(); i != all.end(); ++i ) {
BSONElement sub = *i;
if ( sub.type() != Array )
boost::scoped_ptr<ElementIterator> cursor( doc->getIterator( _elementPath ) );
while ( cursor->more() ) {
ElementIterator::Element e = cursor->next();
if ( e.element().type() != Array )
continue;
if ( _allMatch( sub.Obj() ) ) {
if ( _allMatch( e.element().Obj() ) )
return true;
}
}
return false;
}
Expand Down Expand Up @@ -276,9 +246,8 @@ namespace mongo {
// ---------

Status SizeMatchExpression::init( const StringData& path, int size ) {
_path = path;
_size = size;
return Status::OK();
return initPath( path );
}

bool SizeMatchExpression::matchesArray( const BSONObj& anArray, MatchDetails* details ) const {
Expand All @@ -289,15 +258,15 @@ namespace mongo {

void SizeMatchExpression::debugString( StringBuilder& debug, int level ) const {
_debugAddSpace( debug, level );
debug << _path << " $size : " << _size << "\n";
debug << path() << " $size : " << _size << "\n";
}

bool SizeMatchExpression::equivalent( const MatchExpression* other ) const {
if ( matchType() != other->matchType() )
return false;

const SizeMatchExpression* realOther = static_cast<const SizeMatchExpression*>( other );
return _path == realOther->_path && _size == realOther->_size;
return path() == realOther->path() && _size == realOther->_size;
}


Expand Down
7 changes: 6 additions & 1 deletion src/mongo/db/matcher/expression_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ namespace mongo {
ArrayMatchingMatchExpression( MatchType matchType ) : MatchExpression( matchType ){}
virtual ~ArrayMatchingMatchExpression(){}

Status initPath( const StringData& path );

virtual bool matches( const MatchableDocument* doc, MatchDetails* details ) const;

/**
Expand All @@ -44,8 +46,10 @@ namespace mongo {

bool equivalent( const MatchExpression* other ) const;

protected:
const StringData& path() const { return _path; }
private:
StringData _path;
ElementPath _elementPath;
};


Expand Down Expand Up @@ -114,6 +118,7 @@ namespace mongo {
bool _allMatch( const BSONObj& anArray ) const;

StringData _path;
ElementPath _elementPath;
std::vector< const ArrayMatchingMatchExpression* > _list;
};

Expand Down
3 changes: 1 addition & 2 deletions src/mongo/db/matcher/expression_geo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@
namespace mongo {

Status GeoMatchExpression::init( const StringData& path, const GeoQuery& query ) {
initPath( path );
_query = query;
return Status::OK();
return initPath( path );
}

bool GeoMatchExpression::matchesSingleElement( const BSONElement& e ) const {
Expand Down
Loading

0 comments on commit 2962381

Please sign in to comment.