StatusWithExpression ExpressionParser::_parseNot( const char* name, const BSONElement& e ) { if ( e.type() == RegEx ) { StatusWithExpression s = _parseRegexElement( name, e ); if ( !s.isOK() ) return s; std::auto_ptr<NotExpression> n( new NotExpression() ); Status s2 = n->init( s.getValue() ); if ( !s2.isOK() ) return StatusWithExpression( s2 ); return StatusWithExpression( n.release() ); } if ( e.type() != Object ) return StatusWithExpression( ErrorCodes::BadValue, "$not needs a regex or a document" ); std::auto_ptr<AndExpression> theAnd( new AndExpression() ); Status s = _parseSub( name, e.Obj(), theAnd.get() ); if ( !s.isOK() ) return StatusWithExpression( s ); std::auto_ptr<NotExpression> theNot( new NotExpression() ); s = theNot->init( theAnd.release() ); if ( !s.isOK() ) return StatusWithExpression( s ); return StatusWithExpression( theNot.release() ); }
StatusWithMatchExpression MatchExpressionParser::_parseNot(const char* name, const BSONElement& e, const CollatorInterface* collator, int level) { if (e.type() == RegEx) { StatusWithMatchExpression s = _parseRegexElement(name, e); if (!s.isOK()) return s; std::unique_ptr<NotMatchExpression> n = stdx::make_unique<NotMatchExpression>(); Status s2 = n->init(s.getValue().release()); if (!s2.isOK()) return StatusWithMatchExpression(s2); return {std::move(n)}; } if (e.type() != Object) return StatusWithMatchExpression(ErrorCodes::BadValue, "$not needs a regex or a document"); BSONObj notObject = e.Obj(); if (notObject.isEmpty()) return StatusWithMatchExpression(ErrorCodes::BadValue, "$not cannot be empty"); std::unique_ptr<AndMatchExpression> theAnd = stdx::make_unique<AndMatchExpression>(); Status s = _parseSub(name, notObject, theAnd.get(), collator, level); if (!s.isOK()) return StatusWithMatchExpression(s); // TODO: this seems arbitrary? // tested in jstests/not2.js for (unsigned i = 0; i < theAnd->numChildren(); i++) if (theAnd->getChild(i)->matchType() == MatchExpression::REGEX) return StatusWithMatchExpression(ErrorCodes::BadValue, "$not cannot have a regex"); std::unique_ptr<NotMatchExpression> theNot = stdx::make_unique<NotMatchExpression>(); s = theNot->init(theAnd.release()); if (!s.isOK()) return StatusWithMatchExpression(s); return {std::move(theNot)}; }
StatusWithMatchExpression MatchExpressionParser::_parse( const BSONObj& obj, bool topLevel ) { std::auto_ptr<AndMatchExpression> root( new AndMatchExpression() ); BSONObjIterator i( obj ); while ( i.more() ){ BSONElement e = i.next(); if ( e.fieldName()[0] == '$' ) { const char * rest = e.fieldName() + 1; // TODO: optimize if block? if ( mongoutils::str::equals( "or", rest ) ) { if ( e.type() != Array ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$or needs an array" ); std::auto_ptr<OrMatchExpression> temp( new OrMatchExpression() ); Status s = _parseTreeList( e.Obj(), temp.get() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); root->add( temp.release() ); } else if ( mongoutils::str::equals( "and", rest ) ) { if ( e.type() != Array ) return StatusWithMatchExpression( ErrorCodes::BadValue, "and needs an array" ); std::auto_ptr<AndMatchExpression> temp( new AndMatchExpression() ); Status s = _parseTreeList( e.Obj(), temp.get() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); root->add( temp.release() ); } else if ( mongoutils::str::equals( "nor", rest ) ) { if ( e.type() != Array ) return StatusWithMatchExpression( ErrorCodes::BadValue, "and needs an array" ); std::auto_ptr<NorMatchExpression> temp( new NorMatchExpression() ); Status s = _parseTreeList( e.Obj(), temp.get() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); root->add( temp.release() ); } else if ( mongoutils::str::equals( "atomic", rest ) || mongoutils::str::equals( "isolated", rest ) ) { if ( !topLevel ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$atomic/$isolated has to be at the top level" ); if ( e.trueValue() ) root->add( new AtomicMatchExpression() ); } else if ( mongoutils::str::equals( "where", rest ) ) { /* if ( !topLevel ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$where has to be at the top level" ); */ StatusWithMatchExpression s = expressionParserWhereCallback( e ); if ( !s.isOK() ) return s; root->add( s.getValue() ); } else if ( mongoutils::str::equals( "text", rest ) ) { if ( e.type() != Object ) { return StatusWithMatchExpression( ErrorCodes::BadValue, "$text expects an object" ); } StatusWithMatchExpression s = expressionParserTextCallback( e.Obj() ); if ( !s.isOK() ) { return s; } root->add( s.getValue() ); } else if ( mongoutils::str::equals( "comment", rest ) ) { } else { return StatusWithMatchExpression( ErrorCodes::BadValue, mongoutils::str::stream() << "unknown top level operator: " << e.fieldName() ); } continue; } if ( _isExpressionDocument( e ) ) { Status s = _parseSub( e.fieldName(), e.Obj(), root.get() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); continue; } if ( e.type() == RegEx ) { StatusWithMatchExpression result = _parseRegexElement( e.fieldName(), e ); if ( !result.isOK() ) return result; root->add( result.getValue() ); continue; } std::auto_ptr<ComparisonMatchExpression> eq( new EqualityMatchExpression() ); Status s = eq->init( e.fieldName(), e ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); root->add( eq.release() ); } if ( root->numChildren() == 1 ) { const MatchExpression* real = root->getChild(0); root->clearAndRelease(); return StatusWithMatchExpression( const_cast<MatchExpression*>(real) ); } return StatusWithMatchExpression( root.release() ); }