|
|
@@ -1,836 +1,704 @@
|
|
|
-"use strict"
|
|
|
-
|
|
|
-
|
|
|
+"use strict";
|
|
|
|
|
|
// Autogenerated by cport.py on 2013-09-17 14:37
|
|
|
var MatchExpressionParser = module.exports = function (){
|
|
|
|
|
|
}, klass = MatchExpressionParser, base = Object , proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+// DEPENDENCIES
|
|
|
+var errors = require("../../Errors.js"),
|
|
|
+ ErrorCodes = errors.ErrorCodes,
|
|
|
+ AndMatchExpression = require("./AndMatchExpression.js"),
|
|
|
+ MatchExpression = require("./MatchExpression.js"),
|
|
|
+ OrMatchExpression = require("./OrMatchExpression.js"),
|
|
|
+ ModMatchExpression = require("./ModMatchExpression.js"),
|
|
|
+ NorMatchExpression = require("./NorMatchExpression.js"),
|
|
|
+ NotMatchExpression = require("./NotMatchExpression.js"),
|
|
|
+ LTMatchExpression = require("./LTMatchExpression.js"),
|
|
|
+ LTEMatchExpression = require("./LTEMatchExpression.js"),
|
|
|
+ GTMatchExpression = require("./GTMatchExpression.js"),
|
|
|
+ GTEMatchExpression = require("./GTEMatchExpression.js"),
|
|
|
+ InMatchExpression = require("./InMatchExpression.js"),
|
|
|
+ SizeMatchExpression = require("./SizeMatchExpression.js"),
|
|
|
+ TypeMatchExpression = require("./TypeMatchExpression.js"),
|
|
|
+ ExistsMatchExpression = require("./ExistsMatchExpression.js"),
|
|
|
+ EqualityMatchExpression = require("./EqualityMatchExpression.js"),
|
|
|
+ ArrayMatchingMatchExpression = require("./ArrayMatchingMatchExpression.js"),
|
|
|
+ RegexMatchExpression = require("./RegexMatchExpression.js"),
|
|
|
+ FalseMatchExpression = require("./FalseMatchExpression.js"),
|
|
|
+ ComparisonMatchExpression = require("./ComparisonMatchExpression.js"),
|
|
|
+ ElemMatchValueMatchExpression = require("./ElemMatchValueMatchExpression.js"),
|
|
|
+ ElemMatchObjectMatchExpression = require("./ElemMatchObjectMatchExpression.js"),
|
|
|
+ AllElemMatchOp = require("./AllElemMatchOp.js"),
|
|
|
+ AtomicMatchExpression = require("./AtomicMatchExpression.js");
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _isExpressionDocument
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._isExpressionDocument = function _isExpressionDocument( /* const BSONElement& e */ ){
|
|
|
-
|
|
|
-// File: expression_parser.cpp lines: 340-355
|
|
|
-// bool MatchExpressionParser::_isExpressionDocument( const BSONElement& e ) {
|
|
|
-// if ( e.type() != Object )
|
|
|
-// return false;
|
|
|
-//
|
|
|
-// BSONObj o = e.Obj();
|
|
|
-// if ( o.isEmpty() )
|
|
|
-// return false;
|
|
|
-//
|
|
|
-// const char* name = o.firstElement().fieldName();
|
|
|
-// if ( name[0] != '$' )
|
|
|
-// return false;
|
|
|
-//
|
|
|
-// if ( mongoutils::str::equals( "$ref", name ) )
|
|
|
-// return false;
|
|
|
-//
|
|
|
-// return true;
|
|
|
-// }
|
|
|
+proto._isExpressionDocument = function _isExpressionDocument(element){
|
|
|
+ // File: expression_parser.cpp lines: 340-355
|
|
|
+ if (!(element instanceof Object))
|
|
|
+ return false;
|
|
|
|
|
|
+ if (element.isEmpty())
|
|
|
+ return false;
|
|
|
|
|
|
+ var name = element.keys()[0];
|
|
|
+ if (name[0] != '$')
|
|
|
+ return false;
|
|
|
|
|
|
-}
|
|
|
+ if ("$ref" == name)
|
|
|
+ return false;
|
|
|
|
|
|
+ return true;
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parse
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parse = function _parse( /* const BSONObj& obj, bool topLevel */ ){
|
|
|
-
|
|
|
-// File: expression_parser.cpp lines: 217-319
|
|
|
-// 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( "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() );
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
+proto._parse = function _parse(obj, topLevel){
|
|
|
+ // File: expression_parser.cpp lines: 217-319
|
|
|
+ var rest, temp, status, element, eq, real;
|
|
|
+ var root = new AndMatchExpression();
|
|
|
+
|
|
|
+ for (var i = 0; i < obj.length; i++) {
|
|
|
+ element = obj[i];
|
|
|
+ if (element[0] == '$' ) {
|
|
|
+ rest = element.substr(1, element.length);
|
|
|
+
|
|
|
+ // TODO: optimize if block?
|
|
|
+ if ("or" == rest) {
|
|
|
+ if (!(element instanceof Array))
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$or needs an array"};
|
|
|
+ temp = new OrMatchExpression();
|
|
|
+ status = this._parseTreeList(element, temp.get());
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ root.add(temp.release());
|
|
|
+ }
|
|
|
+ else if ("and" == rest) {
|
|
|
+ if (!(element instanceof Array))
|
|
|
+ return {code:ErrorCodes.BadValue, description:"and needs an array"};
|
|
|
+ temp = new AndMatchExpression();
|
|
|
+ status = this._parseTreeList(element, temp.get());
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ root.add(temp.release());
|
|
|
+ }
|
|
|
+ else if ("nor" == rest) {
|
|
|
+ if (!(element instanceof Array))
|
|
|
+ return {code:ErrorCodes.BadValue, description:"and needs an array"};
|
|
|
+ temp = new NorMatchExpression();
|
|
|
+ status = this._parseTreeList(element, temp.get());
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ root.add(temp.release());
|
|
|
+ }
|
|
|
+ else if (("atomic" == rest) || ("isolated" == rest)) {
|
|
|
+ if (!topLevel)
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$atomic/$isolated has to be at the top level"};
|
|
|
+ if (element)
|
|
|
+ root.add(new AtomicMatchExpression());
|
|
|
+ }
|
|
|
+ else if ("where" == rest) {
|
|
|
+ /*
|
|
|
+ if ( !topLevel )
|
|
|
+ return StatusWithMatchExpression( ErrorCodes::BadValue, "$where has to be at the top level" );
|
|
|
+ */
|
|
|
+ status = this.expressionParserWhereCallback(element);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ root.add(status.result);
|
|
|
+ }
|
|
|
+ else if ("comment" == rest) {
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return {code:ErrorCodes.BadValue, description:"unknown top level operator: " + element};
|
|
|
+ }
|
|
|
+
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this._isExpressionDocument(element)) {
|
|
|
+ status = this._parseSub(element, element, root.get());
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (element instanceof RegExp) {
|
|
|
+ status = this._parseRegexElement(element, element);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ root.add(status.result);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ eq = new EqualityMatchExpression();
|
|
|
+ status = eq.init(element, element);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ root.add(eq.release());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (root.numChildren() == 1) {
|
|
|
+ real = new MatchExpression(root.getChild(0));
|
|
|
+ root.clearAndRelease();
|
|
|
+ return {code:ErrorCodes.OK, result:real};
|
|
|
+ }
|
|
|
+
|
|
|
+ return {code:ErrorCodes.OK, result:root.release()};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parseAll
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parseAll = function _parseAll( /* const char* name,$/;" */ ){
|
|
|
-
|
|
|
-// File: expression_parser.cpp lines: 512-583
|
|
|
-// StatusWithMatchExpression MatchExpressionParser::_parseAll( const char* name,
|
|
|
-// const BSONElement& e ) {
|
|
|
-// if ( e.type() != Array )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "$all needs an array" );
|
|
|
-//
|
|
|
-// BSONObj arr = e.Obj();
|
|
|
-// if ( arr.firstElement().type() == Object &&
|
|
|
-// mongoutils::str::equals( "$elemMatch",
|
|
|
-// arr.firstElement().Obj().firstElement().fieldName() ) ) {
|
|
|
-// // $all : [ { $elemMatch : {} } ... ]
|
|
|
-//
|
|
|
-// std::auto_ptr<AllElemMatchOp> temp( new AllElemMatchOp() );
|
|
|
-// Status s = temp->init( name );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-//
|
|
|
-// BSONObjIterator i( arr );
|
|
|
-// while ( i.more() ) {
|
|
|
-// BSONElement hopefullyElemMatchElement = i.next();
|
|
|
-//
|
|
|
-// if ( hopefullyElemMatchElement.type() != Object ) {
|
|
|
-// // $all : [ { $elemMatch : ... }, 5 ]
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue,
|
|
|
-// "$all/$elemMatch has to be consistent" );
|
|
|
-// }
|
|
|
-//
|
|
|
-// BSONObj hopefullyElemMatchObj = hopefullyElemMatchElement.Obj();
|
|
|
-// if ( !mongoutils::str::equals( "$elemMatch",
|
|
|
-// hopefullyElemMatchObj.firstElement().fieldName() ) ) {
|
|
|
-// // $all : [ { $elemMatch : ... }, { x : 5 } ]
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue,
|
|
|
-// "$all/$elemMatch has to be consistent" );
|
|
|
-// }
|
|
|
-//
|
|
|
-// StatusWithMatchExpression inner = _parseElemMatch( "", hopefullyElemMatchObj.firstElement() );
|
|
|
-// if ( !inner.isOK() )
|
|
|
-// return inner;
|
|
|
-// temp->add( static_cast<ArrayMatchingMatchExpression*>( inner.getValue() ) );
|
|
|
-// }
|
|
|
-//
|
|
|
-// return StatusWithMatchExpression( temp.release() );
|
|
|
-// }
|
|
|
-//
|
|
|
-// std::auto_ptr<AndMatchExpression> myAnd( new AndMatchExpression() );
|
|
|
-// BSONObjIterator i( arr );
|
|
|
-// while ( i.more() ) {
|
|
|
-// BSONElement e = i.next();
|
|
|
-//
|
|
|
-// if ( e.type() == RegEx ) {
|
|
|
-// std::auto_ptr<RegexMatchExpression> r( new RegexMatchExpression() );
|
|
|
-// Status s = r->init( name, e );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// myAnd->add( r.release() );
|
|
|
-// }
|
|
|
-// else if ( e.type() == Object && e.Obj().firstElement().getGtLtOp(-1) != -1 ) {
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "no $ expressions in $all" );
|
|
|
-// }
|
|
|
-// else {
|
|
|
-// std::auto_ptr<EqualityMatchExpression> x( new EqualityMatchExpression() );
|
|
|
-// Status s = x->init( name, e );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// myAnd->add( x.release() );
|
|
|
-// }
|
|
|
-// }
|
|
|
-//
|
|
|
-// if ( myAnd->numChildren() == 0 ) {
|
|
|
-// return StatusWithMatchExpression( new FalseMatchExpression() );
|
|
|
-// }
|
|
|
-//
|
|
|
-// return StatusWithMatchExpression( myAnd.release() );
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
+proto._parseAll = function _parseAll(name, element){
|
|
|
+ // File: expression_parser.cpp lines: 512-583
|
|
|
+ var status, i;
|
|
|
+
|
|
|
+ if (!(element instanceof Array))
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$all needs an array"};
|
|
|
+
|
|
|
+ var arr = element;
|
|
|
+ if ((arr[0] instanceof Object) && ("$elemMatch" == arr[0].keys()[0])) {
|
|
|
+ // $all : [ { $elemMatch : {} } ... ]
|
|
|
+
|
|
|
+ var temp = new AllElemMatchOp();
|
|
|
+ status = temp.init(name);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ for (i = 0; i < arr.length; i++) {
|
|
|
+ var hopefullyElemMatchElement = arr[i];
|
|
|
+
|
|
|
+ if (!(hopefullyElemMatchElement instanceof Object)) {
|
|
|
+ // $all : [ { $elemMatch : ... }, 5 ]
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$all/$elemMatch has to be consistent"};
|
|
|
+ }
|
|
|
+
|
|
|
+ if ("$elemMatch" != hopefullyElemMatchElement.keys()[0]) {
|
|
|
+ // $all : [ { $elemMatch : ... }, { x : 5 } ]
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$all/$elemMatch has to be consistent"};
|
|
|
+ }
|
|
|
+
|
|
|
+ status = this._parseElemMatch("", hopefullyElemMatchElement[hopefullyElemMatchElement.keys()[0]]); // TODO: wrong way to do this?
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ temp.add(new ArrayMatchingMatchExpression(status.result));
|
|
|
+ }
|
|
|
+
|
|
|
+ return {code:ErrorCodes.OK, result:temp.release()};
|
|
|
+ }
|
|
|
+
|
|
|
+ var myAnd = new AndMatchExpression();
|
|
|
+ for (i = 0; i < arr.length; i++) {
|
|
|
+ var e = arr[i];
|
|
|
+
|
|
|
+ if (e instanceof RegExp) {
|
|
|
+ var r = new RegexMatchExpression();
|
|
|
+ status = r.init(name, e);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ myAnd.add(r.release());
|
|
|
+ }
|
|
|
+ else if ((e instanceof Object) && (e.keys()[0].getGtLtOp(-1) != -1)) {
|
|
|
+ return {code:ErrorCodes.BadValue, description:"no $ expressions in $all"};
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ var x = new EqualityMatchExpression();
|
|
|
+ status = x.init(name, e);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ myAnd.add(x.release());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (myAnd.numChildren() === 0) {
|
|
|
+ return {code:ErrorCodes.OK, result:new FalseMatchExpression()};
|
|
|
+ }
|
|
|
+
|
|
|
+ return {code:ErrorCodes.OK, result:myAnd.release()};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parseArrayFilterEntries
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parseArrayFilterEntries = function _parseArrayFilterEntries( /* ArrayFilterEntries* entries,$/;" */ ){
|
|
|
-
|
|
|
-// File: expression_parser.cpp lines: 445-468
|
|
|
-// Status MatchExpressionParser::_parseArrayFilterEntries( ArrayFilterEntries* entries,
|
|
|
-// const BSONObj& theArray ) {
|
|
|
-//
|
|
|
-// BSONObjIterator i( theArray );
|
|
|
-// while ( i.more() ) {
|
|
|
-// BSONElement e = i.next();
|
|
|
-//
|
|
|
-// if ( e.type() == RegEx ) {
|
|
|
-// std::auto_ptr<RegexMatchExpression> r( new RegexMatchExpression() );
|
|
|
-// Status s = r->init( "", e );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return s;
|
|
|
-// s = entries->addRegex( r.release() );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return s;
|
|
|
-// }
|
|
|
-// else {
|
|
|
-// Status s = entries->addEquality( e );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return s;
|
|
|
-// }
|
|
|
-// }
|
|
|
-// return Status::OK();
|
|
|
-//
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
+proto._parseArrayFilterEntries = function _parseArrayFilterEntries(entries, theArray){
|
|
|
+ // File: expression_parser.cpp lines: 445-468
|
|
|
+ var status, e, r;
|
|
|
+ for (var i = 0; i < theArray.length; i++) {
|
|
|
+ e = theArray[i];
|
|
|
+
|
|
|
+ if (e instanceof RegExp ) {
|
|
|
+ r = new RegexMatchExpression();
|
|
|
+ status = r.init("", e);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ status = entries.addRegex(r.release());
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ status = entries.addEquality(e);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return {code:ErrorCodes.OK};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parseComparison
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parseComparison = function _parseComparison( /* const char* name,$/;" */ ){
|
|
|
-
|
|
|
-// File: expression_parser.cpp lines: 34-43
|
|
|
-// StatusWithMatchExpression MatchExpressionParser::_parseComparison( const char* name,
|
|
|
-// ComparisonMatchExpression* cmp,
|
|
|
-// const BSONElement& e ) {
|
|
|
-// std::auto_ptr<ComparisonMatchExpression> temp( cmp );
|
|
|
-//
|
|
|
-// Status s = temp->init( name, e );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression(s);
|
|
|
-//
|
|
|
-// return StatusWithMatchExpression( temp.release() );
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
+proto._parseComparison = function _parseComparison(name, cmp, element){
|
|
|
+ // File: expression_parser.cpp lines: 34-43
|
|
|
+ var temp = new ComparisonMatchExpression(cmp);
|
|
|
|
|
|
-}
|
|
|
+ var status = temp.init(name, element);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
|
|
|
+ return {code:ErrorCodes.OK, result:temp.release()};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parseElemMatch
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parseElemMatch = function _parseElemMatch( /* const char* name,$/;" */ ){
|
|
|
-
|
|
|
-// File: expression_parser.cpp lines: 471-509
|
|
|
-// StatusWithMatchExpression MatchExpressionParser::_parseElemMatch( const char* name,
|
|
|
-// const BSONElement& e ) {
|
|
|
-// if ( e.type() != Object )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "$elemMatch needs an Object" );
|
|
|
-//
|
|
|
-// BSONObj obj = e.Obj();
|
|
|
-// if ( _isExpressionDocument( e ) ) {
|
|
|
-// // value case
|
|
|
-//
|
|
|
-// AndMatchExpression theAnd;
|
|
|
-// Status s = _parseSub( "", obj, &theAnd );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-//
|
|
|
-// std::auto_ptr<ElemMatchValueMatchExpression> temp( new ElemMatchValueMatchExpression() );
|
|
|
-// s = temp->init( name );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-//
|
|
|
-// for ( size_t i = 0; i < theAnd.numChildren(); i++ ) {
|
|
|
-// temp->add( theAnd.getChild( i ) );
|
|
|
-// }
|
|
|
-// theAnd.clearAndRelease();
|
|
|
-//
|
|
|
-// return StatusWithMatchExpression( temp.release() );
|
|
|
-// }
|
|
|
-//
|
|
|
-// // object case
|
|
|
-//
|
|
|
-// StatusWithMatchExpression sub = _parse( obj, false );
|
|
|
-// if ( !sub.isOK() )
|
|
|
-// return sub;
|
|
|
-//
|
|
|
-// std::auto_ptr<ElemMatchObjectMatchExpression> temp( new ElemMatchObjectMatchExpression() );
|
|
|
-// Status status = temp->init( name, sub.getValue() );
|
|
|
-// if ( !status.isOK() )
|
|
|
-// return StatusWithMatchExpression( status );
|
|
|
-//
|
|
|
-// return StatusWithMatchExpression( temp.release() );
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
+proto._parseElemMatch = function _parseElemMatch(name, element){
|
|
|
+ // File: expression_parser.cpp lines: 471-509
|
|
|
+ var temp, status;
|
|
|
+ if (!(element instanceof Object))
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$elemMatch needs an Object"};
|
|
|
+
|
|
|
+ if (this._isExpressionDocument(element)) {
|
|
|
+ // value case
|
|
|
+
|
|
|
+ var theAnd = new AndMatchExpression();
|
|
|
+ status = this._parseSub("", element, theAnd);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ temp = new ElemMatchValueMatchExpression();
|
|
|
+ status = temp.init(name);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ for (var i = 0; i < theAnd.numChildren(); i++ ) {
|
|
|
+ temp.add(theAnd.getChild(i));
|
|
|
+ }
|
|
|
+ theAnd.clearAndRelease();
|
|
|
+
|
|
|
+ return {code:ErrorCodes.OK, result:temp.release()};
|
|
|
+ }
|
|
|
+
|
|
|
+ // object case
|
|
|
+
|
|
|
+ status = this._parse(element, false);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ temp = new ElemMatchObjectMatchExpression();
|
|
|
+ status = temp.init(name, status.result);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
|
|
|
+ return {code:ErrorCodes.OK, result:temp.release()};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parseMOD
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parseMOD = function _parseMOD( /* const char* name,$/;" */ ){
|
|
|
-
|
|
|
-// File: expression_parser.cpp lines: 360-387
|
|
|
-// StatusWithMatchExpression MatchExpressionParser::_parseMOD( const char* name,
|
|
|
-// const BSONElement& e ) {
|
|
|
-//
|
|
|
-// if ( e.type() != Array )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, needs to be an array" );
|
|
|
-//
|
|
|
-// BSONObjIterator i( e.Obj() );
|
|
|
-//
|
|
|
-// if ( !i.more() )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, not enough elements" );
|
|
|
-// BSONElement d = i.next();
|
|
|
-// if ( !d.isNumber() )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, divisor not a number" );
|
|
|
-//
|
|
|
-// if ( !i.more() )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, not enough elements" );
|
|
|
-// BSONElement r = i.next();
|
|
|
-// if ( !d.isNumber() )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, remainder not a number" );
|
|
|
-//
|
|
|
-// if ( i.more() )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, too many elements" );
|
|
|
-//
|
|
|
-// std::auto_ptr<ModMatchExpression> temp( new ModMatchExpression() );
|
|
|
-// Status s = temp->init( name, d.numberInt(), r.numberInt() );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// return StatusWithMatchExpression( temp.release() );
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
+proto._parseMOD = function _parseMOD(name, element){
|
|
|
+ // File: expression_parser.cpp lines: 360-387
|
|
|
+
|
|
|
+ if (!(element instanceof Array))
|
|
|
+ return {code:ErrorCodes.BadValue, result:"malformed mod, needs to be an array"};
|
|
|
+ if (element.length < 2)
|
|
|
+ return {code:ErrorCodes.BadValue, result:"malformed mod, not enough elements"};
|
|
|
+ if (element.length > 2)
|
|
|
+ return {code:ErrorCodes.BadValue, result:"malformed mod, too many elements"};
|
|
|
+ if (!(element[0] instanceof Number))
|
|
|
+ return {code:ErrorCodes.BadValue, result:"malformed mod, divisor not a number"};
|
|
|
+ if (!(element[1] instanceof Number))
|
|
|
+ return {code:ErrorCodes.BadValue, result:"malformed mod, remainder not a number"};
|
|
|
+
|
|
|
+ var temp = new ModMatchExpression();
|
|
|
+ var status = temp.init( name, element[0], element[1]);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ return {code:ErrorCodes.OK, result:temp.release()};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parseNot
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parseNot = function _parseNot( /* const char* name,$/;" */ ){
|
|
|
-
|
|
|
-// File: expression_parser_tree.cpp lines: 55-91
|
|
|
-// StatusWithMatchExpression MatchExpressionParser::_parseNot( const char* name,
|
|
|
-// const BSONElement& e ) {
|
|
|
-// if ( e.type() == RegEx ) {
|
|
|
-// StatusWithMatchExpression s = _parseRegexElement( name, e );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return s;
|
|
|
-// std::auto_ptr<NotMatchExpression> n( new NotMatchExpression() );
|
|
|
-// Status s2 = n->init( s.getValue() );
|
|
|
-// if ( !s2.isOK() )
|
|
|
-// return StatusWithMatchExpression( s2 );
|
|
|
-// return StatusWithMatchExpression( n.release() );
|
|
|
-// }
|
|
|
-//
|
|
|
-// 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::auto_ptr<AndMatchExpression> theAnd( new AndMatchExpression() );
|
|
|
-// Status s = _parseSub( name, notObject, theAnd.get() );
|
|
|
-// 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::auto_ptr<NotMatchExpression> theNot( new NotMatchExpression() );
|
|
|
-// s = theNot->init( theAnd.release() );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-//
|
|
|
-// return StatusWithMatchExpression( theNot.release() );
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
+proto._parseNot = function _parseNot(name, element){
|
|
|
+ // File: expression_parser_tree.cpp lines: 55-91
|
|
|
+ var status;
|
|
|
+ if (element instanceof RegExp) {
|
|
|
+ status = this._parseRegexElement(name, element);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ var n = new NotMatchExpression();
|
|
|
+ status = n.init(status.result);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ return {code:ErrorCodes.OK, result:n.release()};
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(element instanceof Object))
|
|
|
+ return {code:ErrorCodes.BadValue, result:"$not needs a regex or a document"};
|
|
|
+
|
|
|
+ if (element == {})
|
|
|
+ return {code:ErrorCodes.BadValue, result:"$not cannot be empty"};
|
|
|
+
|
|
|
+ var theAnd = new AndMatchExpression();
|
|
|
+ status = this._parseSub(name, element, theAnd.get());
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ // TODO: this seems arbitrary?
|
|
|
+ // tested in jstests/not2.js
|
|
|
+ for (var i = 0; i < theAnd.numChildren(); i++)
|
|
|
+ if (theAnd.getChild(i).matchType == MatchExpression.REGEX)
|
|
|
+ return {code:ErrorCodes.BadValue, result:"$not cannot have a regex"};
|
|
|
+
|
|
|
+ var theNot = new NotMatchExpression();
|
|
|
+ status = theNot.init(theAnd.release());
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ return {code:ErrorCodes.OK, result:theNot.release()};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parseRegexDocument
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parseRegexDocument = function _parseRegexDocument( /* const char* name,$/;" */ ){
|
|
|
-
|
|
|
-// File: expression_parser.cpp lines: 402-442
|
|
|
-// StatusWithMatchExpression MatchExpressionParser::_parseRegexDocument( const char* name,
|
|
|
-// const BSONObj& doc ) {
|
|
|
-// string regex;
|
|
|
-// string regexOptions;
|
|
|
-//
|
|
|
-// BSONObjIterator i( doc );
|
|
|
-// while ( i.more() ) {
|
|
|
-// BSONElement e = i.next();
|
|
|
-// switch ( e.getGtLtOp() ) {
|
|
|
-// case BSONObj::opREGEX:
|
|
|
-// if ( e.type() == String ) {
|
|
|
-// regex = e.String();
|
|
|
-// }
|
|
|
-// else if ( e.type() == RegEx ) {
|
|
|
-// regex = e.regex();
|
|
|
-// regexOptions = e.regexFlags();
|
|
|
-// }
|
|
|
-// else {
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue,
|
|
|
-// "$regex has to be a string" );
|
|
|
-// }
|
|
|
-//
|
|
|
-// break;
|
|
|
-// case BSONObj::opOPTIONS:
|
|
|
-// if ( e.type() != String )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue,
|
|
|
-// "$options has to be a string" );
|
|
|
-// regexOptions = e.String();
|
|
|
-// break;
|
|
|
-// default:
|
|
|
-// break;
|
|
|
-// }
|
|
|
-//
|
|
|
-// }
|
|
|
-//
|
|
|
-// std::auto_ptr<RegexMatchExpression> temp( new RegexMatchExpression() );
|
|
|
-// Status s = temp->init( name, regex, regexOptions );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// return StatusWithMatchExpression( temp.release() );
|
|
|
-//
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
+proto._parseRegexDocument = function _parseRegexDocument(name, doc){
|
|
|
+ // File: expression_parser.cpp lines: 402-442
|
|
|
+ var regex, regexOptions, e;
|
|
|
+
|
|
|
+ for (var i = 0; i < doc.length; i++) {
|
|
|
+ e = doc[i];
|
|
|
+ switch (e.getGtLtOp()) {
|
|
|
+ case 'opREGEX':
|
|
|
+ if (e instanceof String) {
|
|
|
+ regex = e;
|
|
|
+ }
|
|
|
+ else if (e instanceof RegExp) {
|
|
|
+ var str = e.toString(),
|
|
|
+ flagIndex = 0;
|
|
|
+ for (var c = str.length; c > 0; c--){
|
|
|
+ if (str[c] == '/') {
|
|
|
+ flagIndex = c;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ regex = str.substr(1, flagIndex-1);
|
|
|
+ regexOptions = str.substr(flagIndex, str.length);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$regex has to be a string"};
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ case 'opOPTIONS':
|
|
|
+ if (!(e instanceof String))
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$options has to be a string"};
|
|
|
+ regexOptions = e;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var temp = new RegexMatchExpression();
|
|
|
+ var status = temp.init(name, regex, regexOptions);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ return {code:ErrorCodes.OK, result:temp.release()};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parseRegexElement
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parseRegexElement = function _parseRegexElement( /* const char* name,$/;" */ ){
|
|
|
-
|
|
|
-// File: expression_parser.cpp lines: 390-399
|
|
|
-// StatusWithMatchExpression MatchExpressionParser::_parseRegexElement( const char* name,
|
|
|
-// const BSONElement& e ) {
|
|
|
-// if ( e.type() != RegEx )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "not a regex" );
|
|
|
-//
|
|
|
-// std::auto_ptr<RegexMatchExpression> temp( new RegexMatchExpression() );
|
|
|
-// Status s = temp->init( name, e.regex(), e.regexFlags() );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// return StatusWithMatchExpression( temp.release() );
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
+proto._parseRegexElement = function _parseRegexElement(name, element){
|
|
|
+ // File: expression_parser.cpp lines: 390-399
|
|
|
+ if (!(element instanceof RegExp))
|
|
|
+ return {code:ErrorCodes.BadValue, description:"not a regex"};
|
|
|
+
|
|
|
+ var str = element.toString(),
|
|
|
+ flagIndex = 0;
|
|
|
+ for (var c = str.length; c > 0; c--){
|
|
|
+ if (str[c] == '/') {
|
|
|
+ flagIndex = c;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var regex = str.substr(1, flagIndex-1),
|
|
|
+ regexOptions = str.substr(flagIndex, str.length),
|
|
|
+ temp = new RegexMatchExpression(),
|
|
|
+ status = temp.init(name, regex, regexOptions);
|
|
|
+
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ return {code:ErrorCodes.OK, result:temp.release()};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parseSub
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parseSub = function _parseSub( /* const char* name,$/;" */ ){
|
|
|
+proto._parseSub = function _parseSub(name, sub, root){
|
|
|
+ // File: expression_parser.cpp lines: 322-337
|
|
|
+ for (var i = 0; i < sub.length; i++) {
|
|
|
+ var deep = sub[i];
|
|
|
|
|
|
-// File: expression_parser.cpp lines: 322-337
|
|
|
-// Status MatchExpressionParser::_parseSub( const char* name,
|
|
|
-// const BSONObj& sub,
|
|
|
-// AndMatchExpression* root ) {
|
|
|
-// BSONObjIterator j( sub );
|
|
|
-// while ( j.more() ) {
|
|
|
-// BSONElement deep = j.next();
|
|
|
-//
|
|
|
-// StatusWithMatchExpression s = _parseSubField( sub, root, name, deep );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return s.getStatus();
|
|
|
-//
|
|
|
-// if ( s.getValue() )
|
|
|
-// root->add( s.getValue() );
|
|
|
-// }
|
|
|
-//
|
|
|
-// return Status::OK();
|
|
|
-// }
|
|
|
+ var status = this._parseSubField(sub, root, name, deep);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
|
|
|
+ if (status.result)
|
|
|
+ root.add(status.result);
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
+ return {code:ErrorCodes.OK};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parseSubField
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parseSubField = function _parseSubField( /* const BSONObj& context,$/;" */ ){
|
|
|
-
|
|
|
-// File: expression_parser.cpp lines: 46-214
|
|
|
-// StatusWithMatchExpression MatchExpressionParser::_parseSubField( const BSONObj& context,
|
|
|
-// const AndMatchExpression* andSoFar,
|
|
|
-// const char* name,
|
|
|
-// const BSONElement& e ) {
|
|
|
-//
|
|
|
-// // TODO: these should move to getGtLtOp, or its replacement
|
|
|
-//
|
|
|
-// if ( mongoutils::str::equals( "$eq", e.fieldName() ) )
|
|
|
-// return _parseComparison( name, new EqualityMatchExpression(), e );
|
|
|
-//
|
|
|
-// if ( mongoutils::str::equals( "$not", e.fieldName() ) ) {
|
|
|
-// return _parseNot( name, e );
|
|
|
-// }
|
|
|
-//
|
|
|
-// int x = e.getGtLtOp(-1);
|
|
|
-// switch ( x ) {
|
|
|
-// case -1:
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue,
|
|
|
-// mongoutils::str::stream() << "unknown operator: "
|
|
|
-// << e.fieldName() );
|
|
|
-// case BSONObj::LT:
|
|
|
-// return _parseComparison( name, new LTMatchExpression(), e );
|
|
|
-// case BSONObj::LTE:
|
|
|
-// return _parseComparison( name, new LTEMatchExpression(), e );
|
|
|
-// case BSONObj::GT:
|
|
|
-// return _parseComparison( name, new GTMatchExpression(), e );
|
|
|
-// case BSONObj::GTE:
|
|
|
-// return _parseComparison( name, new GTEMatchExpression(), e );
|
|
|
-// case BSONObj::NE: {
|
|
|
-// StatusWithMatchExpression s = _parseComparison( name, new EqualityMatchExpression(), e );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return s;
|
|
|
-// std::auto_ptr<NotMatchExpression> n( new NotMatchExpression() );
|
|
|
-// Status s2 = n->init( s.getValue() );
|
|
|
-// if ( !s2.isOK() )
|
|
|
-// return StatusWithMatchExpression( s2 );
|
|
|
-// return StatusWithMatchExpression( n.release() );
|
|
|
-// }
|
|
|
-// case BSONObj::Equality:
|
|
|
-// return _parseComparison( name, new EqualityMatchExpression(), e );
|
|
|
-//
|
|
|
-// case BSONObj::opIN: {
|
|
|
-// if ( e.type() != Array )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "$in needs an array" );
|
|
|
-// std::auto_ptr<InMatchExpression> temp( new InMatchExpression() );
|
|
|
-// Status s = temp->init( name );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// s = _parseArrayFilterEntries( temp->getArrayFilterEntries(), e.Obj() );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// return StatusWithMatchExpression( temp.release() );
|
|
|
-// }
|
|
|
-//
|
|
|
-// case BSONObj::NIN: {
|
|
|
-// if ( e.type() != Array )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "$nin needs an array" );
|
|
|
-// std::auto_ptr<InMatchExpression> temp( new InMatchExpression() );
|
|
|
-// Status s = temp->init( name );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// s = _parseArrayFilterEntries( temp->getArrayFilterEntries(), e.Obj() );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-//
|
|
|
-// std::auto_ptr<NotMatchExpression> temp2( new NotMatchExpression() );
|
|
|
-// s = temp2->init( temp.release() );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-//
|
|
|
-// return StatusWithMatchExpression( temp2.release() );
|
|
|
-// }
|
|
|
-//
|
|
|
-// case BSONObj::opSIZE: {
|
|
|
-// int size = 0;
|
|
|
-// if ( e.type() == String ) {
|
|
|
-// // matching old odd semantics
|
|
|
-// size = 0;
|
|
|
-// }
|
|
|
-// else if ( e.type() == NumberInt || e.type() == NumberLong ) {
|
|
|
-// size = e.numberInt();
|
|
|
-// }
|
|
|
-// else if ( e.type() == NumberDouble ) {
|
|
|
-// if ( e.numberInt() == e.numberDouble() ) {
|
|
|
-// size = e.numberInt();
|
|
|
-// }
|
|
|
-// else {
|
|
|
-// // old semantcs require exact numeric match
|
|
|
-// // so [1,2] != 1 or 2
|
|
|
-// size = -1;
|
|
|
-// }
|
|
|
-// }
|
|
|
-// else {
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "$size needs a number" );
|
|
|
-// }
|
|
|
-//
|
|
|
-// std::auto_ptr<SizeMatchExpression> temp( new SizeMatchExpression() );
|
|
|
-// Status s = temp->init( name, size );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// return StatusWithMatchExpression( temp.release() );
|
|
|
-// }
|
|
|
-//
|
|
|
-// case BSONObj::opEXISTS: {
|
|
|
-// if ( e.eoo() )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "$exists can't be eoo" );
|
|
|
-// std::auto_ptr<ExistsMatchExpression> temp( new ExistsMatchExpression() );
|
|
|
-// Status s = temp->init( name );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// if ( e.trueValue() )
|
|
|
-// return StatusWithMatchExpression( temp.release() );
|
|
|
-// std::auto_ptr<NotMatchExpression> temp2( new NotMatchExpression() );
|
|
|
-// s = temp2->init( temp.release() );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// return StatusWithMatchExpression( temp2.release() );
|
|
|
-// }
|
|
|
-//
|
|
|
-// case BSONObj::opTYPE: {
|
|
|
-// if ( !e.isNumber() )
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "$type has to be a number" );
|
|
|
-// int type = e.numberInt();
|
|
|
-// if ( e.type() != NumberInt && type != e.number() )
|
|
|
-// type = -1;
|
|
|
-// std::auto_ptr<TypeMatchExpression> temp( new TypeMatchExpression() );
|
|
|
-// Status s = temp->init( name, type );
|
|
|
-// if ( !s.isOK() )
|
|
|
-// return StatusWithMatchExpression( s );
|
|
|
-// return StatusWithMatchExpression( temp.release() );
|
|
|
-// }
|
|
|
-//
|
|
|
-//
|
|
|
-// case BSONObj::opMOD:
|
|
|
-// return _parseMOD( name, e );
|
|
|
-//
|
|
|
-// case BSONObj::opOPTIONS: {
|
|
|
-// // TODO: try to optimize this
|
|
|
-// // we have to do this since $options can be before or after a $regex
|
|
|
-// // but we validate here
|
|
|
-// BSONObjIterator i( context );
|
|
|
-// while ( i.more() ) {
|
|
|
-// BSONElement temp = i.next();
|
|
|
-// if ( temp.getGtLtOp( -1 ) == BSONObj::opREGEX )
|
|
|
-// return StatusWithMatchExpression( NULL );
|
|
|
-// }
|
|
|
-//
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue, "$options needs a $regex" );
|
|
|
-// }
|
|
|
-//
|
|
|
-// case BSONObj::opREGEX: {
|
|
|
-// return _parseRegexDocument( name, context );
|
|
|
-// }
|
|
|
-//
|
|
|
-// case BSONObj::opELEM_MATCH:
|
|
|
-// return _parseElemMatch( name, e );
|
|
|
-//
|
|
|
-// case BSONObj::opALL:
|
|
|
-// return _parseAll( name, e );
|
|
|
-//
|
|
|
-// case BSONObj::opWITHIN:
|
|
|
-// case BSONObj::opGEO_INTERSECTS:
|
|
|
-// case BSONObj::opNEAR:
|
|
|
-// return expressionParserGeoCallback( name, x, context );
|
|
|
-//
|
|
|
-// }
|
|
|
-//
|
|
|
-// return StatusWithMatchExpression( ErrorCodes::BadValue,
|
|
|
-// mongoutils::str::stream() << "not handled: " << e.fieldName() );
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
+proto._parseSubField = function _parseSubField(context, andSoFar, name, element){
|
|
|
+ // File: expression_parser.cpp lines: 46-214
|
|
|
+ // TODO: these should move to getGtLtOp, or its replacement
|
|
|
+
|
|
|
+ if ("$eq" == element)
|
|
|
+ return this._parseComparison(name, new EqualityMatchExpression(), element);
|
|
|
+
|
|
|
+ if ("$not" == element) {
|
|
|
+ return this._parseNot(name, element);
|
|
|
+ }
|
|
|
+
|
|
|
+ var x = element.getGtLtOp(-1),
|
|
|
+ status, temp, temp2;
|
|
|
+ switch (x) {
|
|
|
+ case -1:
|
|
|
+ return {code:ErrorCodes.BadValue, description:"unknown operator: " + element};
|
|
|
+ case 'LT':
|
|
|
+ return this._parseComparison(name, new LTMatchExpression(), element);
|
|
|
+ case 'LTE':
|
|
|
+ return this._parseComparison(name, new LTEMatchExpression(), element);
|
|
|
+ case 'GT':
|
|
|
+ return this._parseComparison(name, new GTMatchExpression(), element);
|
|
|
+ case 'GTE':
|
|
|
+ return this._parseComparison(name, new GTEMatchExpression(), element);
|
|
|
+ case 'NE':
|
|
|
+ status = this._parseComparison(name, new EqualityMatchExpression(), element);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ var n = new NotMatchExpression();
|
|
|
+ status = n.init(status.result);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ return {code:ErrorCodes.OK, result:n.release()};
|
|
|
+ case 'Equality':
|
|
|
+ return this._parseComparison(name, new EqualityMatchExpression(), element);
|
|
|
+
|
|
|
+ case 'opIN':
|
|
|
+ if (!(element instanceof Array))
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$in needs an array"};
|
|
|
+ temp = new InMatchExpression();
|
|
|
+ status = temp.init(name);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ status = this._parseArrayFilterEntries(temp.getArrayFilterEntries(), element);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ return {code:ErrorCodes.OK, result:temp.release()};
|
|
|
+
|
|
|
+ case 'NIN':
|
|
|
+ if (!(element instanceof Array))
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$nin needs an array"};
|
|
|
+ temp = new InMatchExpression();
|
|
|
+ status = temp.init(name);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ status = this._parseArrayFilterEntries(temp.getArrayFilterEntries(), element);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ temp2 = new NotMatchExpression();
|
|
|
+ status = temp2.init(temp.release());
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ return {code:ErrorCodes.OK, result:temp2.release()};
|
|
|
+
|
|
|
+ case 'opSIZE':
|
|
|
+ var size = 0;
|
|
|
+ if (element instanceof String)
|
|
|
+ // matching old odd semantics
|
|
|
+ size = 0;
|
|
|
+ else if (element instanceof Number)
|
|
|
+ size = element;
|
|
|
+ else {
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$size needs a number"};
|
|
|
+ }
|
|
|
+
|
|
|
+ temp = new SizeMatchExpression();
|
|
|
+ status = temp.init(name, size);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ return {code:ErrorCodes.OK, result:temp.release()};
|
|
|
+
|
|
|
+ case 'opEXISTS':
|
|
|
+ if (element == {})
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$exists can't be eoo"};
|
|
|
+ temp = new ExistsMatchExpression();
|
|
|
+ status = temp.init(name);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ if (element)
|
|
|
+ return {code:ErrorCodes.OK, result:temp.release()};
|
|
|
+ temp2 = new NotMatchExpression();
|
|
|
+ status = temp2.init(temp.release());
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ return {code:ErrorCodes.OK, result:temp2.release()};
|
|
|
+
|
|
|
+ case 'opTYPE':
|
|
|
+ if (!(element instanceof Number))
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$type has to be a number"};
|
|
|
+ var type = element;
|
|
|
+ temp = new TypeMatchExpression();
|
|
|
+ status = temp.init(name, type);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+ return {code:ErrorCodes.OK, result:temp.release()};
|
|
|
+
|
|
|
+ case 'opMOD':
|
|
|
+ return this._parseMOD(name, element);
|
|
|
+
|
|
|
+ case 'opOPTIONS':
|
|
|
+ // TODO: try to optimize this
|
|
|
+ // we have to do this since $options can be before or after a $regex
|
|
|
+ // but we validate here
|
|
|
+ for(var i = 0; i < context.length; i++) {
|
|
|
+ temp = context[i];
|
|
|
+ if (temp.getGtLtOp(-1) == 'opREGEX')
|
|
|
+ return {code:ErrorCodes.OK, result:null};
|
|
|
+ }
|
|
|
+
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$options needs a $regex"};
|
|
|
+
|
|
|
+ case 'opREGEX':
|
|
|
+ return this._parseRegexDocument(name, context);
|
|
|
+
|
|
|
+ case 'opELEM_MATCH':
|
|
|
+ return this._parseElemMatch(name, element);
|
|
|
+
|
|
|
+ case 'opALL':
|
|
|
+ return this._parseAll(name, element);
|
|
|
+
|
|
|
+ case 'opWITHIN':
|
|
|
+ case 'opGEO_INTERSECTS':
|
|
|
+ case 'opNEAR':
|
|
|
+ return this.expressionParserGeoCallback(name, x, context);
|
|
|
+
|
|
|
+ } // end switch
|
|
|
+
|
|
|
+ return {code:ErrorCodes.BadValue, description:"not handled: " + element};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method _parseTreeList
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto._parseTreeList = function _parseTreeList( /* const BSONObj& arr, ListOfMatchExpression* out */ ){
|
|
|
-
|
|
|
-// File: expression_parser_tree.cpp lines: 33-52
|
|
|
-// Status MatchExpressionParser::_parseTreeList( const BSONObj& arr, ListOfMatchExpression* out ) {
|
|
|
-// if ( arr.isEmpty() )
|
|
|
-// return Status( ErrorCodes::BadValue,
|
|
|
-// "$and/$or/$nor must be a nonempty array" );
|
|
|
-//
|
|
|
-// BSONObjIterator i( arr );
|
|
|
-// while ( i.more() ) {
|
|
|
-// BSONElement e = i.next();
|
|
|
-//
|
|
|
-// if ( e.type() != Object )
|
|
|
-// return Status( ErrorCodes::BadValue,
|
|
|
-// "$or/$and/$nor entries need to be full objects" );
|
|
|
-//
|
|
|
-// StatusWithMatchExpression sub = _parse( e.Obj(), false );
|
|
|
-// if ( !sub.isOK() )
|
|
|
-// return sub.getStatus();
|
|
|
-//
|
|
|
-// out->add( sub.getValue() );
|
|
|
-// }
|
|
|
-// return Status::OK();
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
+proto._parseTreeList = function _parseTreeList(arr, out){
|
|
|
+ // File: expression_parser_tree.cpp lines: 33-52
|
|
|
+ if (arr.length === 0)
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$and/$or/$nor must be a nonempty array"};
|
|
|
+
|
|
|
+ var status, element;
|
|
|
+ for (var i = 0; i < arr.length; i++) {
|
|
|
+ element = arr[i];
|
|
|
+
|
|
|
+ if (!(element instanceof Object))
|
|
|
+ return {code:ErrorCodes.BadValue, description:"$or/$and/$nor entries need to be full objects"};
|
|
|
|
|
|
+ status = this._parse(element, false);
|
|
|
+ if (status.code != ErrorCodes.OK)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ out.add(status.result);
|
|
|
+ }
|
|
|
+ return {code:ErrorCodes.OK};
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* This documentation was automatically generated. Please update when you touch this function.
|
|
|
* @method parse
|
|
|
* @param
|
|
|
*
|
|
|
*/
|
|
|
-proto.parse = function parse( /* const BSONObj& obj */ ){
|
|
|
-// File: expression_parser.h lines: 40-41
|
|
|
-// static StatusWithMatchExpression parse( const BSONObj& obj ) {
|
|
|
-// return _parse( obj, true );
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
+proto.parse = function parse(obj){
|
|
|
+ // File: expression_parser.h lines: 40-41
|
|
|
+ return this._parse(obj, true);
|
|
|
+};
|