Browse Source

EAGLESIX-2688 Minor changes. Added error codes to some Errors. Commented out a duplicate method.

Tony Ennis 11 years ago
parent
commit
7eb7da8d8d
1 changed files with 59 additions and 41 deletions
  1. 59 41
      lib/pipeline/expressions/Expression.js

+ 59 - 41
lib/pipeline/expressions/Expression.js

@@ -26,10 +26,10 @@ var Expression = module.exports = function Expression() {
     });
 
 
-
-function fn(){
-	return;
-}
+//NOTE: DEVIATION FROM MONGO: What is this?
+//function fn(){
+//	return;
+//}
 
 
 // NESTED CLASSES
@@ -74,18 +74,38 @@ var ObjectCtx = Expression.ObjectCtx = (function() {
 	return klass;
 })();
 
-proto.removeFieldPrefix = function removeFieldPrefix(prefixedField) {
-	if (prefixedField.indexOf("\0") !== -1) {
-		// field path must not contain embedded null characters - 16419
-	}
-	if (prefixedField[0] !== '$') {
-		// "field path references must be prefixed with a '$'"
-	}
-	return prefixedField.slice(1);
-};
+//NOTE: DEVIATION FROM MONGO: This probably isn't a deviation. #removeFieldPrefix has been duplicated possibly accidently.
+// there is only one use of removeFieldPrefix in all of mungedb-aggregate.  This is in UnwindDocumentSource and it refers to the klass version.
+//
+//proto.removeFieldPrefix = function removeFieldPrefix(prefixedField) {
+//	if (prefixedField.indexOf("\0") !== -1) {
+//		throw new Error("field path must not contain embedded null characters; code 16419");
+//	}
+//	if (prefixedField[0] !== '$') {
+//		throw new Error("field path references must be prefixed with a '$'; code 15982");
+//	}
+//	return prefixedField.slice(1);
+//};
+
 var KIND_UNKNOWN = 0,
 	KIND_NOTOPERATOR = 1,
 	KIND_OPERATOR = 2;
+
+
+/**
+ * Produce a field path string with the field prefix removed.
+ * Throws an error if the field prefix is not present.
+ *
+ * @static
+ * @param prefixedField the prefixed field
+ * @returns the field path with the prefix removed
+ **/
+klass.removeFieldPrefix = function removeFieldPrefix(prefixedField) {
+	if (prefixedField.indexOf("\0") != -1) throw new Error("field path must not contain embedded null characters; code 16419");
+	if (prefixedField[0] !== "$") throw new Error("field path references must be prefixed with a '$' ('" + prefixedField + "'); code 15982");
+	return prefixedField.substr(1);
+};
+
 /**
  * Parse an Object.  The object could represent a functional expression or a Document expression.
  *
@@ -98,14 +118,15 @@ var KIND_UNKNOWN = 0,
  * @method parseObject
  * @param obj   the element representing the object
  * @param ctx   a MiniCtx representing the options above
+ * @param vps	Variables Parse State
  * @returns the parsed Expression
  **/
 klass.parseObject = function parseObject(obj, ctx, vps) {
-	if (!(ctx instanceof ObjectCtx)) throw new Error("ctx must be ObjectCtx");
+	if (!(ctx instanceof ObjectCtx)) throw new Error("ctx must be ObjectCtx");	//NOTE: DEVIATION FROM MONGO: This check is not in the c++ code
 	var kind = KIND_UNKNOWN,
 		pExpression, // the result
 		pExpressionObject; // the alt result
-	if (obj === undefined || obj == {}) return new ObjectExpression();
+	if (obj === undefined || obj == {}) return new ObjectExpression();	//NOTE: DEVIATION FROM MONGO: is {} really empty in this context?
 	var fieldNames = Object.keys(obj);
 	if (fieldNames.length === 0) { //NOTE: Added this for mongo 2.5 port of document sources. Should reconsider when porting the expressions themselves
 		return new ObjectExpression();
@@ -115,12 +136,12 @@ klass.parseObject = function parseObject(obj, ctx, vps) {
 
 		if (pFieldName[0] === "$") {
 			if (fieldCount !== 0)
-				throw new Error("the operator must be the only field in a pipeline object (at '" + pFieldName + "'.; code 16410");
+				throw new Error("the operator must be the only field in a pipeline object (at '" + pFieldName + "'.; code 15983");
 
 			if (ctx.isTopLevel)
 				throw new Error("$expressions are not allowed at the top-level of $project; code 16404");
 			kind = KIND_OPERATOR; //we've determined this "object" is an operator expression
-			pExpression = Expression.parseExpression(pFieldName, obj[pFieldName], vps);
+			pExpression = Expression.parseExpression(pFieldName, obj[pFieldName], vps); //NOTE: DEVIATION FROM MONGO: c++ code uses 2 arguments. See #parseExpression
 		} else {
 			if (kind === KIND_OPERATOR)
 				throw new Error("this object is already an operator expression, and can't be used as a document expression (at '" + pFieldName + "'.; code 15990");
@@ -130,13 +151,16 @@ klass.parseObject = function parseObject(obj, ctx, vps) {
 			if (pExpression === undefined) { // if it's our first time, create the document expression
 				if (!ctx.isDocumentOk)
 					throw new Error("document not allowed in this context"); // CW TODO error: document not allowed in this context
-				pExpression = pExpressionObject = new ObjectExpression(); //check for top level?
+				pExpression = pExpressionObject = new ObjectExpression(); //check for top level? //NOTE: DEVIATION FROM MONGO: the c++ calls createRoot() or create() here.
 				kind = KIND_NOTOPERATOR; //this "object" is not an operator expression
 			}
 			var fieldValue = obj[pFieldName];
 			switch (typeof(fieldValue)) {
 				case "object":
 					// it's a nested document
+					//NOTE: DEVIATION FROM MONGO: the behavior here differs from that of the c++ code. The c++ code will
+					// set document_ok or inclusion_ok.  This code sets both values leaving ObjectCtx to figure out
+					// which to use.
 					var subCtx = new ObjectCtx({
 						isDocumentOk: ctx.isDocumentOk,
 						isInclusionOk: ctx.isInclusionOk
@@ -145,7 +169,7 @@ klass.parseObject = function parseObject(obj, ctx, vps) {
 					break;
 				case "string":
 					// it's a renamed field         // CW TODO could also be a constant
-					var pathExpr = new FieldPathExpression.parse(fieldValue);
+					var pathExpr = new FieldPathExpression.parse(fieldValue, vps);
 					pExpressionObject.addField(pFieldName, pathExpr);
 					break;
 				case "boolean":
@@ -156,13 +180,13 @@ klass.parseObject = function parseObject(obj, ctx, vps) {
 							throw new Error("field inclusion is not allowed inside of $expressions; code 16420");
 						pExpressionObject.includePath(pFieldName);
 					} else {
-						if (!(ctx.isTopLevel && fn == Document.ID_PROPERTY_NAME))
+						if (!(ctx.isTopLevel && fn === Document.ID_PROPERTY_NAME))
 							throw new Error("The top-level " + Document.ID_PROPERTY_NAME + " field is the only field currently supported for exclusion; code 16406");
 						pExpressionObject.excludeId = true;
 					}
 					break;
 				default:
-					throw new Error("disallowed field type " + (fieldValue ? fieldValue.constructor.name + ":" : "") + typeof(fieldValue) + " in object expression (at '" + pFieldName + "')");
+					throw new Error("disallowed field type " + (fieldValue ? fieldValue.constructor.name + ":" : "") + typeof(fieldValue) + " in object expression (at '" + pFieldName + "') code 15992");
 			}
 		}
 	}
@@ -172,12 +196,17 @@ klass.parseObject = function parseObject(obj, ctx, vps) {
 
 klass.expressionParserMap = {};
 
+/** Registers an ExpressionParser so it can be called from parseExpression and friends.
+ *
+ *  As an example, if your expression looks like {"$foo": [1,2,3]} you would add this line:
+ *  REGISTER_EXPRESSION("$foo", ExpressionFoo::parse);
+ */
 klass.registerExpression = function registerExpression(key, parserFunc) {
 	if (key in klass.expressionParserMap) {
-		throw new Error("Duplicate expression registrarion for " + key);
+		throw new Error("Duplicate expression registration for " + key + "; code 17064");
 	}
 	klass.expressionParserMap[key] = parserFunc;
-	return 0; // Should
+	return 1;	//NOTE: DEVIATION FROM MONGO: Mongo returns Status::OK()/
 };
 
 /**
@@ -189,13 +218,18 @@ klass.registerExpression = function registerExpression(key, parserFunc) {
  * @param obj   the BSONElement to parse
  * @returns the parsed Expression
  **/
+//NOTE: DEVIATION FROM MONGO: the c++ version has 2 arguments, not 3.
 klass.parseExpression = function parseExpression(exprKey, exprValue, vps) {
 	if (!(exprKey in Expression.expressionParserMap)) {
-		throw new Error("Invalid operator : " + exprKey);
+		throw new Error("Invalid operator : " + exprKey + "; code 15999");
 	}
 	return Expression.expressionParserMap[exprKey](exprValue, vps);
 };
 
+//NOTE: DEVIATION FROM MONGO: The c++ code includes a method here called ExpressionNary::parseArguments(...)
+// This is missing from the code you're currently looking at.  I am not sure it is a bad thing as it seems
+// like it should be in the NaryExpression class.
+
 /**
  * Parse a BSONElement which is an operand in an Expression.
  *
@@ -207,29 +241,13 @@ klass.parseOperand = function parseOperand(exprElement, vps) {
 	var t = typeof(exprElement);
 	if (t === "string" && exprElement[0] == "$") { //if we got here, this is a field path expression
 	    return new FieldPathExpression.parse(exprElement, vps);
-	} else
-	if (t === "object" && exprElement && exprElement.constructor === Object)
+	} else if (t === "object" && exprElement && exprElement.constructor === Object)
 		return Expression.parseObject(exprElement, new ObjectCtx({
 			isDocumentOk: true
 		}), vps);
 	else return ConstantExpression.parse(exprElement, vps);
 };
 
-/**
- * Produce a field path string with the field prefix removed.
- * Throws an error if the field prefix is not present.
- *
- * @static
- * @param prefixedField the prefixed field
- * @returns the field path with the prefix removed
- **/
-klass.removeFieldPrefix = function removeFieldPrefix(prefixedField) {
-	if (prefixedField.indexOf("\0") != -1) throw new Error("field path must not contain embedded null characters; code 16419");
-	if (prefixedField[0] !== "$") throw new Error("field path references must be prefixed with a '$' ('" + prefixedField + "'); code 15982");
-	return prefixedField.substr(1);
-};
-
-
 // PROTOTYPE MEMBERS
 /**
  * Evaluate the Expression using the given document as input.