Bläddra i källkod

Merge branch 'feature/mongo_2.6.5_matcher' into feature/mongo_2.6.5_matcher_Equality

* feature/mongo_2.6.5_matcher: (22 commits)
  EAGLESIX-2992: === instead of ==.
  EAGLESIX-2992: Organizing the code to be better understood.
  EAGLESIX-2653: Fix a jshint error for paths
  EAGLESIX-2992: Porting code; building initial test cases.
  EAGLESIX-2653 added _matches back to ElementPath since we dont have time to fully implement the mongo version
  EAGLESIX-2985: Fixed jshint issue
  EAGLESIX-3003: Using reference to class.
  EAGLESIX-3003: Fixed up test cases.
  EAGLESIX-3009: Removed unnecessary memory related functions
  EAGLESIX-3003: Added a period (.).
  EAGLESIX-3003: Cleaned up test cases and some of hte code on the class.
  EAGLESIX-2985: Fixed up debugString
  EAGLESIX-3003: Ported mongo 2.6.5 code.
  EAGLESIX-2653 updated ElementPath to mongo 2.6.5.  removed the _matches function as it does not exist in the mongo code
  EAGLESIX-2984: Fixed an debugString and shallowClone
  EAGLESIX-3002: Fixed debugString and removed verbose comments
  EAGLESIX-3009: NotMatchExpress now v2.6.5 compliant
  EAGLESIX-3002: InMatchExpression v2.6.5 compliant
  EAGLESIX-2984: Updated ElemMatchObjectMatchExpression 2.6.5
  port ElemMatchValueMatch
  ...

Conflicts:
	lib/pipeline/matcher/ElementPath.js
Chris Sexton 11 år sedan
förälder
incheckning
4f6e3cb733

+ 17 - 23
lib/pipeline/matcher/ElemMatchObjectMatchExpression.js

@@ -1,12 +1,10 @@
 "use strict";
 var ArrayMatchingMatchExpression = require('./ArrayMatchingMatchExpression.js');
 
-// Autogenerated by cport.py on 2013-09-17 14:37
 var ElemMatchObjectMatchExpression = module.exports = function ElemMatchObjectMatchExpression(){
 	base.call(this);
 }, klass = ElemMatchObjectMatchExpression, base = ArrayMatchingMatchExpression, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
-// File: expression_array.h lines: 77-77
 proto._sub = undefined;
 
 /**
@@ -17,21 +15,28 @@ proto._sub = undefined;
  *
  */
 proto.debugString = function debugString(level){
-	// File: expression_array.cpp lines: 106-109
-	var debug = this._debugAddSpace(level);
-	debug = debug + this.path() + " $elemMatch\n";
-	return debug + this._sub.debugString(level + 1);
+	return this._debugAddSpace( level ) + this.path() + " $elemMatch (obj) " + (this.getTag() ? this.getTag().debugString() : '') + this._exp._debugString( level + 1 );
+};
+
+/**
+ *
+ * Return 1 since we have a single "sub"
+ * @method numChildren
+ *
+ */
+proto.numChildren = function numChildren(){
+	return 1;
 };
 
 /**
  *
  * Return the _sub property
  * @method getChild
+ * @param i
  *
  */
-proto.getChild = function getChild(){
-	// File: expression_array.h lines: 74-73
-	return this._sub;
+proto.getChild = function getChild(i){
+	return this._sub.get();
 };
 
 /**
@@ -43,7 +48,6 @@ proto.getChild = function getChild(){
  *
  */
 proto.init = function init(path, sub){
-	// File: expression_array.cpp lines: 85-87
 	this._sub = sub;
 	return this.initPath(path);
 };
@@ -57,7 +61,6 @@ proto.init = function init(path, sub){
  *
  */
 proto.matchesArray = function matchesArray(anArray, details){
-	// File: expression_array.cpp lines: 90-103
 	for (var i in anArray) {
 		var inner = anArray[i];
 		if (!(inner instanceof Object))
@@ -72,17 +75,6 @@ proto.matchesArray = function matchesArray(anArray, details){
 	return false;
 };
 
-/**
- *
- * Return 1 since we have a single "sub"
- * @method numChildren
- *
- */
-proto.numChildren = function numChildren(){
-	// File: expression_array.h lines: 73-72
-	return 1;
-};
-
 /**
  *
  * clone this instance to a new one
@@ -90,8 +82,10 @@ proto.numChildren = function numChildren(){
  *
  */
 proto.shallowClone = function shallowClone(){
-	// File: expression_array.h lines: 65-68
 	var element = new ElemMatchObjectMatchExpression();
 	element.init(this.path(), this._sub.shallowClone());
+	if ( this.getTag() ){
+		element.setTag(this.getTag().clone());
+	}
 	return element;
 };

+ 6 - 13
lib/pipeline/matcher/ElemMatchValueMatchExpression.js

@@ -1,7 +1,6 @@
 "use strict";
 var ArrayMatchingMatchExpression = require('./ArrayMatchingMatchExpression.js');
 
-// Autogenerated by cport.py on 2013-09-17 14:37
 var ElemMatchValueMatchExpression = module.exports = function ElemMatchValueMatchExpression(){
 	base.call(this);
 	this._matchType = 'ELEM_MATCH_VALUE';
@@ -12,7 +11,6 @@ var ElemMatchValueMatchExpression = module.exports = function ElemMatchValueMatc
 var errors = require("../../Errors.js"),
 	ErrorCodes = errors.ErrorCodes;
 
-// File: expression_array.h lines: 108-108
 proto._subs = undefined;
 
 /**
@@ -23,7 +21,6 @@ proto._subs = undefined;
  *
  */
 proto._arrayElementMatchesAll = function _arrayElementMatchesAll(element){
-	// File: expression_array.cpp lines: 152-157
 	for (var i = 0; i < this._subs.length; i++ ) {
 		if (!this._subs[i].matchesSingleElement(element))
 			return false;
@@ -39,7 +36,6 @@ proto._arrayElementMatchesAll = function _arrayElementMatchesAll(element){
  *
  */
 proto.add = function add(sub){
-	// File: expression_array.cpp lines: 132-134
 	if (!sub) throw new Error(sub + " ElemMatchValueMatchExpression:36");
 	this._subs.push(sub);
 };
@@ -52,11 +48,9 @@ proto.add = function add(sub){
  *
  */
 proto.debugString = function debugString(level){
-	// File: expression_array.cpp lines: 160-165
-	var debug = this._debugAddSpace(level);
-	debug = debug + this.path() + " $elemMatch\n";
+	var debug = this._debugAddSpace(level) + this.path() + " $elemMatch (value)" + (this.getTag() ? this.getTag().debugString() : '') + "\n";
 	for (var i = 0; i < this._subs.length; i++) {
-		debug = debug + this._subs[i].debugString(level + 1);
+		debug += this._subs[i].debugString(level + 1);
 	}
 	return debug;
 };
@@ -69,7 +63,6 @@ proto.debugString = function debugString(level){
  *
  */
 proto.getChild = function getChild(i){
-	// File: expression_array.h lines: 103-102
 	return this._subs[i];
 };
 
@@ -82,7 +75,6 @@ proto.getChild = function getChild(i){
  *
  */
 proto.init = function init(path, sub){
-	// File: expression_array.cpp lines: 121-124
 	this.initPath(path);
 	if (sub)
 		this.add(sub);
@@ -98,7 +90,6 @@ proto.init = function init(path, sub){
  *
  */
 proto.matchesArray = function matchesArray(anArray, details){
-	// File: expression_array.cpp lines: 137-149
 	for (var i in anArray) {
 		var inner = anArray[i];
 
@@ -119,7 +110,6 @@ proto.matchesArray = function matchesArray(anArray, details){
  *
  */
 proto.numChildren = function numChildren(){
-	// File: expression_array.h lines: 102-101
 	return this._subs.length;
 };
 
@@ -130,11 +120,14 @@ proto.numChildren = function numChildren(){
  *
  */
 proto.shallowClone = function shallowClone(){
-	// File: expression_array.h lines: 91-97
 	var element = new ElemMatchValueMatchExpression();
 	element.init(this.path());
 	for (var i = 0; i < this._subs.length; ++i) {
 		element.add(this._subs[i].shallowClone());
 	}
+	var td = this.getTag();
+	if (td) {
+		element.setTag(td.clone());
+	}
 	return element;
 };

+ 21 - 23
lib/pipeline/matcher/ElementPath.js

@@ -1,14 +1,15 @@
 "use strict";
 
-var FieldRef = require('./FieldRef');
+var FieldRef = require('./FieldRef'),
+	ErrorCodes = require('../../Errors.js').ErrorCodes;
 
 var ElementPath = module.exports = function ElementPath(){
 	this._fieldRef = new FieldRef();
 	this._shouldTraverseLeafArray = false;
 }, klass = ElementPath, base =  Object  , proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
-
 proto._fieldRef = undefined;
+
 proto._shouldTraverseLeafArray = undefined;
 
 /**
@@ -20,7 +21,6 @@ proto._shouldTraverseLeafArray = undefined;
  * @param idxPathObj This is an object with a pathID element. This allows for pass by ref in calling function.
  * */
 klass.getFieldDottedOrArray = function getFieldDottedOrArray(doc, path, idxPathObj){
-	// File path_internal.cpp lines 31-72
 	if (path.numParts() === 0 ) { return doc; }
 
 	var res,curr = doc,
@@ -28,7 +28,7 @@ klass.getFieldDottedOrArray = function getFieldDottedOrArray(doc, path, idxPathO
 		partNum = 0;
 	while (partNum < path.numParts() && !stop) {
 		res = curr[path.getPart( partNum)];
-		if(res == {}){
+		if(res instanceof Object && Object.keys(res).length === 0){
 			stop = true;
 		} else if (res instanceof Object) {
 			curr = res;
@@ -44,7 +44,7 @@ klass.getFieldDottedOrArray = function getFieldDottedOrArray(doc, path, idxPathO
 
 	}
 
-	//idxPathObj.pathID = partNum;
+	idxPathObj.pathID = partNum;
 	return res;
 };
 
@@ -56,7 +56,6 @@ klass.getFieldDottedOrArray = function getFieldDottedOrArray(doc, path, idxPathO
  */
 
 klass.isAllDigits = function isAllDigits ( str ){
-	// File path_internal.cpp lines 23-29
 	var digitCheck = /\D/g;
 	if (digitCheck.exec(str) === null){ return true; }
 	return false;
@@ -73,7 +72,7 @@ klass.isAllDigits = function isAllDigits ( str ){
  * @param
  *
  */
-proto.fieldRef = function fieldRef( /*  */ ){
+proto.fieldRef = function fieldRef(){
 	return this._fieldRef;
 };
 
@@ -85,10 +84,10 @@ proto.fieldRef = function fieldRef( /*  */ ){
  * @param path
  *
  */
-proto.init = function init( path ){  //  const StringData& path
+proto.init = function init( path ){
 	this._shouldTraverseLeafArray = true;
 	this._fieldRef.parse( path );
-	return {'code':'OK'};
+	return {'code':ErrorCodes.OK};
 };
 
 
@@ -99,8 +98,7 @@ proto.init = function init( path ){  //  const StringData& path
  * @param
  *
  */
-proto.setTraverseLeafArray = function setTraverseLeafArray( b ){ //  bool b
-// File: path.h lines: 35-34
+proto.setTraverseLeafArray = function setTraverseLeafArray( b ){
 	this._shouldTraverseLeafArray = b;
 };
 
@@ -112,27 +110,27 @@ proto.setTraverseLeafArray = function setTraverseLeafArray( b ){ //  bool b
  * @param
  *
  */
-proto.shouldTraverseLeafArray = function shouldTraverseLeafArray( /*  */ ){
-// File: path.h lines: 38-37
+proto.shouldTraverseLeafArray = function shouldTraverseLeafArray( ){
 	return this._shouldTraverseLeafArray;
 };
 
+
 proto.objAtPath = function objAtPath(doc) {
 	return klass.objAtPath(doc, this._fieldRef._path);
 };
 
 klass.objAtPath = function objAtPath(doc, path) {
-	if(path.length === 0) {
+	if (path.length === 0) {
 		return doc;
 	}
-	if (path.length > 0 && Object.keys(doc).length === 0){
+	if (path.length > 0 && Object.keys(doc).length === 0) {
 		return {};
 	}
 	if (doc === null || doc === undefined) {
 		return doc;
 	}
 	var tpath = path.split('.');
-	return klass.objAtPath(doc[tpath[0]],tpath.slice(1).join('.'));
+	return klass.objAtPath(doc[tpath[0]], tpath.slice(1).join('.'));
 };
 
 
@@ -165,10 +163,10 @@ klass._matches = function _matches(doc, path, shouldTraverseLeafArray, details,
 		curr = doc,
 		item = doc;
 	for (k = 0; k < path.length; k++) {
-		if((curr instanceof Object) && (path[k] in curr)) {
+		if ((curr instanceof Object) && (path[k] in curr)) {
 			item = curr[path[k]];
 		}
-		if(path[k].length === 0)
+		if (path[k].length === 0)
 			continue;
 		item = curr[path[k]];
 		if (item instanceof Object && item.constructor === Object) {
@@ -183,7 +181,7 @@ klass._matches = function _matches(doc, path, shouldTraverseLeafArray, details,
 			curr = item;
 			continue;
 		} else if (item instanceof Object && item.constructor === Array) {
-			if (k == path.length-1) {
+			if (k == path.length - 1) {
 				if ((shouldTraverseLeafArray) && (isNaN(parseInt(path[k], 10)))) {
 					for (ii = 0, il = item.length; ii < il; ii++) {
 						result = checker(item[ii]);
@@ -193,18 +191,18 @@ klass._matches = function _matches(doc, path, shouldTraverseLeafArray, details,
 							return result;
 						}
 					}
-					if(item.length === 0)
+					if (item.length === 0)
 						return checker({});
-					
+
 				}
 				curr = item;
 				break; // this is the end of the path, so check this array
-			} else if (!(isNaN(parseInt(path[k+1], 10)))) {
+			} else if (!(isNaN(parseInt(path[k + 1], 10)))) {
 				curr = item;
 				continue; // the *next* path section is an item in the array so we don't check this whole array
 			}
 			// otherwise, check each item in the array against the rest of the path
-			for(ii = 0, il = item.length; ii < il; ii++){
+			for (ii = 0, il = item.length; ii < il; ii++) {
 				var subitem = item[ii];
 				if (!subitem || subitem.constructor !== Object) continue;	// can't look for a subfield in a non-object value.
 				if (this._matches(subitem, path.slice(k), shouldTraverseLeafArray, null, checker)) { // check the item against the rest of the path

+ 19 - 9
lib/pipeline/matcher/FalseMatchExpression.js

@@ -1,9 +1,14 @@
 "use strict";
 var MatchExpression = require('./MatchExpression');
 
-
-// Autogenerated by cport.py on 2013-09-17 14:37
-var FalseMatchExpression = module.exports = function FalseMatchExpression(){
+/**
+ * A match expression that always returns false
+ * @class FalseMatchExpression
+ * @namespace mungedb-aggregate.pipeline.matcher
+ * @module mungedb-aggregate
+ * @constructor
+ **/
+ var FalseMatchExpression = module.exports = function FalseMatchExpression(){
 	base.call(this);
 	this._matchType = 'ALWAYS_FALSE';
 }, klass = FalseMatchExpression, base =  MatchExpression, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
@@ -16,7 +21,6 @@ var FalseMatchExpression = module.exports = function FalseMatchExpression(){
  *
  */
 proto.debugString = function debugString(level) {
-	// File: expression.cpp lines: 53-55
 	return this._debugAddSpace( level ) + "$false\n";
 };
 
@@ -28,8 +32,7 @@ proto.debugString = function debugString(level) {
  *
  */
 proto.equivalent = function equivalent(other) {
-	// File: expression.h lines: 222-223
-	return other._matchType === 'ALWAYS_FALSE';
+	return other._matchType === this._matchType;
 };
 
 /**
@@ -41,7 +44,6 @@ proto.equivalent = function equivalent(other) {
  *
  */
 proto.matches = function matches(doc,details) {
-	// File: expression.h lines: 208-209
 	return false;
 };
 
@@ -53,7 +55,6 @@ proto.matches = function matches(doc,details) {
  *
  */
 proto.matchesSingleElement = function matchesSingleElement(e) {
-	// File: expression.h lines: 212-213
 	return false;
 };
 
@@ -64,7 +65,16 @@ proto.matchesSingleElement = function matchesSingleElement(e) {
  *
  */
 proto.shallowClone = function shallowClone(){
-	// File: expression.h lines: 216-217
 	return new FalseMatchExpression();
 };
 
+/**
+ *
+ * append to JSON object
+ * @method shallowClone
+ *
+ */
+proto.toJson = function toJson(out){
+	out.$false = 1;
+	return out;
+};

+ 58 - 65
lib/pipeline/matcher/InMatchExpression.js

@@ -1,7 +1,6 @@
 "use strict";
 var LeafMatchExpression = require('./LeafMatchExpression');
 
-// Autogenerated by cport.py on 2013-09-17 14:37
 var InMatchExpression = module.exports = function InMatchExpression(){
 	base.call(this);
 	this._matchType = 'MATCH_IN';
@@ -13,9 +12,19 @@ var errors = require("../../Errors.js"),
 	ErrorCodes = errors.ErrorCodes,
 	ArrayFilterEntries = require("./ArrayFilterEntries.js");
 
-// File: expression_leaf.h lines: 294-294
 proto._arrayEntries = null;
 
+/**
+ *
+ * Initialize the necessary items
+ * @method init
+ * @param path
+ *
+ */
+proto.init = function init(path) {
+	return this.initPath( path );
+};
+
 /**
  *
  * Check if the input element matches a real element
@@ -24,7 +33,6 @@ proto._arrayEntries = null;
  *
  */
 proto._matchesRealElement = function _matchesRealElement(e) {
-	// File: expression_leaf.cpp lines: 422-431
 	if(this._arrayEntries.contains(e)) { // array wrapper.... so no e "in" array
 		return true;
 	}
@@ -33,14 +41,14 @@ proto._matchesRealElement = function _matchesRealElement(e) {
 		if(e.match && e.match(this._arrayEntries.regex(i)._regex)) {
 			return true;
 		} else if (e instanceof RegExp) {
-			if(e.toString() == this._arrayEntries.regex(i)._regex.toString()) {
+			if(e.toString() === this._arrayEntries.regex(i)._regex.toString()) {
 				return true;
 			}
 		}
 	}
 
-	if(typeof(e) == 'undefined') {
-		return true; // Every Set contains the Null Set, man.
+	if(typeof(e) === 'undefined') {
+		return true; // Every Set contains the Null Set.
 	}
 
 	return false;
@@ -48,15 +56,27 @@ proto._matchesRealElement = function _matchesRealElement(e) {
 
 /**
  *
- * Copy our array to the input array
- * @method copyTo
- * @param toFillIn
+ * Check if the input element matches
+ * @method matchesSingleElement
+ * @param e
  *
  */
-proto.copyTo = function copyTo(toFillIn) {
-	// File: expression_leaf.cpp lines: 481-483
-	toFillIn.init(this.path());
-	this._arrayEntries.copyTo( toFillIn._arrayEntries );
+proto.matchesSingleElement = function matchesSingleElement(e) {
+	if( this._arrayEntries === null && typeof(e) == 'object' && Object.keys(e).length === 0) {
+		return true;
+	}
+	if (this._matchesRealElement( e )) {
+		return true;
+	}
+	/*if (e instanceof Array){
+		for (var i = 0; i < e.length; i++) {
+			if(this._matchesRealElement( e[i] )) {
+				return true;
+			}
+		}
+
+	}*/
+	return false;
 };
 
 /**
@@ -67,8 +87,7 @@ proto.copyTo = function copyTo(toFillIn) {
  *
  */
 proto.debugString = function debugString(level) {
-	// File: expression_leaf.cpp lines: 455-463
-	return this._debugAddSpace( level ) + this.path() + ";$in: TODO " + (this.getTag() ? this.getTag().debugString() : '') + "\n";
+	return this._debugAddSpace( level ) + this.path() + " $in " + this._arrayEntries + (this.getTag() ? this.getTag().debugString() : '') + "\n";
 };
 
 /**
@@ -79,83 +98,57 @@ proto.debugString = function debugString(level) {
  *
  */
 proto.equivalent = function equivalent(other) {
-	// File: expression_leaf.cpp lines: 466-472
 	if ( other._matchType != 'MATCH_IN' ) {
 		return false;
 	}
-	return this.path() == other.path() && this._arrayEntries.equivalent( other._arrayEntries );
+	return this.path() === other.path() && this._arrayEntries.equivalent( other._arrayEntries );
 };
 
 /**
  *
- * Return the _arrayEntries property
- * @method getArrayFilterEntries
+ * clone this instance to a new one
+ * @method shallowClone
  *
  */
-proto.getArrayFilterEntries = function getArrayFilterEntries(){
-	// File: expression_leaf.h lines: 280-279
-	return this._arrayEntries;
+proto.shallowClone = function shallowClone(){
+	var e = new InMatchExpression();
+	this.copyTo( e );
+	if ( this.getTag() ){
+		e.setTag(this.getTag().Clone());
+	}
+	return e;
 };
 
 /**
  *
- * Return the _arrayEntries property
- * @method getData
+ * Copy our array to the input array
+ * @method copyTo
+ * @param toFillIn
  *
  */
-proto.getData = function getData(){
-	// File: expression_leaf.h lines: 290-289
-	return this._arrayEntries;
+proto.copyTo = function copyTo(toFillIn) {
+	toFillIn.init(this.path());
+	this._arrayEntries.copyTo( toFillIn._arrayEntries );
 };
 
 /**
  *
- * Initialize the necessary items
- * @method init
- * @param path
+ * Return the _arrayEntries property
+ * @method getArrayFilterEntries
  *
  */
-proto.init = function init(path) {
-	// File: expression_leaf.cpp lines: 418-419
-	return this.initPath( path );
+proto.getArrayFilterEntries = function getArrayFilterEntries(){
+	return this._arrayEntries;
 };
 
 /**
  *
- * Check if the input element matches
- * @method matchesSingleElement
- * @param e
+ * Return the _arrayEntries property
+ * @method getData
  *
  */
-proto.matchesSingleElement = function matchesSingleElement(e) {
-	// File: expression_leaf.cpp lines: 434-452
-	if( this._arrayEntries === null && typeof(e) == 'object' && Object.keys(e).length === 0) {
-		return true;
-	}
-	if (this._matchesRealElement( e )) {
-		return true;
-	}
-	/*if (e instanceof Array){
-		for (var i = 0; i < e.length; i++) {
-			if(this._matchesRealElement( e[i] )) {
-				return true;
-			}
-		}
-
-	}*/
-	return false;
+proto.getData = function getData(){
+	return this._arrayEntries;
 };
 
-/**
- *
- * clone this instance to a new one
- * @method shallowClone
- *
- */
-proto.shallowClone = function shallowClone(){
-	// File: expression_leaf.cpp lines: 475-478
-	var e = new InMatchExpression();
-	this.copyTo( e );
-	return e;
-};
 

+ 9 - 16
lib/pipeline/matcher/NotMatchExpression.js

@@ -1,13 +1,10 @@
 "use strict";
 var MatchExpression = require('./MatchExpression');
-
-	// Autogenerated by cport.py on 2013-09-17 14:37
 var NotMatchExpression = module.exports = function NotMatchExpression(){
 	base.call(this);
 	this._matchType = 'NOT';
 }, klass = NotMatchExpression, base =  Object  , proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
-	// File: expression_tree.h lines: 152-152
 proto._exp = undefined;
 
 /**
@@ -18,7 +15,6 @@ proto._exp = undefined;
  *
  */
 proto.debugString = function debugString(level) {
-	// File: expression_tree.cpp lines: 146-149
 	return this._debugAddSpace( level ) + "$not\n" + this._exp._debugString( level + 1 );
 };
 
@@ -30,19 +26,17 @@ proto.debugString = function debugString(level) {
  *
  */
 proto.equivalent = function equivalent(other) {
-	// File: expression_tree.cpp lines: 152-156
 	return other._matchType == 'NOT' && this._exp.equivalent(other.getChild(0));
 };
 
 /**
  *
- * Return the _exp property
- * @method getChild
+ * Return the reset child
+ * @method resetChild
  *
  */
-proto.getChild = function getChild() {
-	// File: expression_tree.h lines: 148-147
-	return this._exp;
+proto.resetChild = function resetChild(newChild) {
+	this._exp.reset(newChild);
 };
 
 /**
@@ -53,7 +47,6 @@ proto.getChild = function getChild() {
  *
  */
 proto.init = function init(exp) {
-	// File: expression_tree.h lines: 123-125
 	this._exp = exp;
 	return {'code':'OK'};
 };
@@ -66,9 +59,8 @@ proto.init = function init(exp) {
  * @param details
  *
  */
-proto.matches = function matches(doc,details) {
-	// File: expression_tree.h lines: 135-136
-	return ! this._exp.matches( doc,null );
+proto.matches = function matches(doc, details) {
+	return ! this._exp.matches(doc, null);
 };
 
 /**
@@ -79,7 +71,6 @@ proto.matches = function matches(doc,details) {
  *
  */
 proto.matchesSingleElement = function matchesSingleElement(e) {
-	// File: expression_tree.h lines: 139-140
 	return ! this._exp.matchesSingleElement( e );
 };
 
@@ -91,7 +82,6 @@ proto.matchesSingleElement = function matchesSingleElement(e) {
  *
  */
 proto.numChildren = function numChildren(){
-	// File: expression_tree.h lines: 147-146
 	return 1;
 };
 
@@ -105,6 +95,9 @@ proto.shallowClone = function shallowClone(){
 	// File: expression_tree.h lines: 128-132
 	var e = new NotMatchExpression();
 	e.init(this._exp.shallowClone());
+	if ( this.getTag() ) {
+		e.setTag(this.getTag().clone());
+	}
 	return e;
 };
 

+ 97 - 98
lib/pipeline/matcher/TypeMatchExpression.js

@@ -1,163 +1,162 @@
 "use strict";
+
 var MatchExpression = require('./MatchExpression');
 var ElementPath = require('./ElementPath');
 
-// Autogenerated by cport.py on 2013-09-17 14:37
-var TypeMatchExpression = module.exports = function TypeMatchExpression(){
-	base.call(this);
-	this._elementPath = new ElementPath();
-	this._matchType = 'TYPE_OPERATOR';
-}, klass = TypeMatchExpression, base =  MatchExpression, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
+var TypeMatchExpression = module.exports = function TypeMatchExpression() {
+	base.call(this, 'TYPE_OPERATOR');
 
+	this._elementPath = new ElementPath();
+}, klass = TypeMatchExpression, base =  MatchExpression, proto = klass.prototype = Object.create(base.prototype, {constructor: {value: klass}});
 
-// File: expression_leaf.h lines: 338-338
 proto._elementPath = undefined;
-
-// File: expression_leaf.h lines: 337-337
 proto._path = undefined;
-
-// File: expression_leaf.h lines: 339-339
 proto._type = undefined;
 
 /**
+ * Initialize the current object.
  *
- * Writes a debug string for this object
- * @method debugString
- * @param level
- *
+ * @param path
+ * @param type
+ * @returns {*}
  */
-proto.debugString = function debugString(level) {
-	// File: expression_leaf.cpp lines: 335-343
-	return this._debugAddSapce( level ) + this.path() + " type: " + this._type + (this.getTag() ? this.getTag().debugString() : '' ) + "\n";
+proto.init = function init(path, type) {
+	this._path = path;
+	this._type = type;
+
+	return this._elementPath.init(path);
 };
 
 /**
  *
- * checks if this expression is == to the other
- * @method equivalent
- * @param other
+ * Returns a shallow copy of the instance.
  *
+ * @returns {TypeMatchExpression}
  */
-proto.equivalent = function equivalent(other) {
-	// File: expression_leaf.cpp lines: 347-352
-	if( other._matchType != 'TYPE_OPERATOR' ) {
-		return false;
+proto.shallowClone = function shallowClone(){
+	var clone = new TypeMatchExpression();
+
+	clone.init(this._path, this._type);
+
+	if (this.getTag()) {
+		clone.setTag(this.getTag().clone());
 	}
-	return this._path == other._path && this._type == other._type;
+
+	return clone;
 };
 
 /**
+ * Used number reference to types like the C++ enum (?).
  *
- * Return the _type property
- * @method getData
- *
+ * @param e
+ * @returns {number}
  */
-proto.getData = function getData(){
-	// File: expression_leaf.h lines: 328-327
-	return this._type;
+klass.type = function type(e) {
+	if(e === undefined) {
+		return 6;
+	} else if (e === null) {
+		return 10;
+	}
+
+	switch (typeof e) {
+		case 'number':
+			return 1;
+		case 'string':
+			return 2;
+		case 'boolean':
+			return 8;
+		case 'object':
+			if (e instanceof Array) {
+				return 4;
+			} else if (e instanceof RegExp) {
+				return 11;
+			} else if (e instanceof Date) {
+				return 9;
+			} else if (e.constructor.name === 'MinKey') {
+				return -1;
+			} else if (e.constructor.name === 'MaxKey') {
+				return 127;
+			}
+	}
+
+	return 42;
 };
 
 /**
+ * Matches single element.
  *
- * Initialize the necessary items
- * @method init
- * @param path
- * @param type
- *
+ * @param e
+ * @returns {boolean}
  */
-proto.init = function init(path,type) {
-	// File: expression_leaf.cpp lines: 308-311
-	this._path = path;
-	this._type = type;
-	return this._elementPath.init( path );
+proto.matchesSingleElement = function matchesSingleElement(e) {
+	return klass.type(e) === this._type;
 };
 
 /**
+ * Matches against the document.
  *
- * matches checks the input doc against the internal element path to see if it is a match
- * @method matches
  * @param doc
  * @param details
- *
+ * @returns {*}
  */
-proto.matches = function matches(doc,details) {
-	// File: expression_leaf.cpp lines: 318-332
+proto.matches = function matches(doc, details) {
 	var self = this,
-		checker = function(element) {
-			if (!self.matchesSingleElement(element, details))
+		matcher = function matcher(element) {
+			if (!self.matchesSingleElement(element, details)) {
 				return false;
+			}
 
-			//var amIRoot = (element.length === 0);		
 			return true;
 		};
-	return this._elementPath._matches(doc, details, checker);
+
+	return this._elementPath._matches(doc, details, matcher);
 };
 
 /**
- * Return a number indicating the type of the input element
- * @method typeNumber
- * @param e
+ * Writes a debug string for this object.
  *
+ * @param level
+ * @returns {string}
  */
-klass.typeNumber = function typeNumber(e){
-	if(e === undefined)
-		return 6;
-	if(e === null)
-		return 10;
-	if(typeof(e) == 'number')
-		return 1;
-	if(typeof(e) == 'string')
-		return 2;
-	if(typeof(e) == 'boolean')
-		return 8;
-	if(typeof(e) == 'object') {
-		if(e instanceof Array)
-			return 4;
-		if(e instanceof RegExp)
-			return 11;
-		if(e instanceof Date)
-			return 9;
-		if(e.constructor.name == 'MinKey')
-			return -1;
-		if(e.constructor.name == 'MAxKey')
-			return 127;
+proto.debugString = function debugString(level) {
+	var rtn  = this._debugAddSpace(level) + this.path() + ' type: ' + this._type;
+
+	if (this.getTag()) {
+		rtn += ' ' + this.getTag().debugString();
 	}
-	return 42; // Can't tell
+
+	return rtn + '\n';
 };
 
 /**
+ * Checks to see if the other instance is equivalent to the current instance.
  *
- * Check if the input element matches
- * @method matchesSingleElement
- * @param e
- *
+ * @param other
+ * @returns {boolean}
  */
-proto.matchesSingleElement = function matchesSingleElement(e) {
-	// File: expression_leaf.cpp lines: 314-315
-	return klass.typeNumber( e ) == this._type;
+proto.equivalent = function equivalent(other) {
+	if (this.matchType() !== other.matchType()) {
+		return false;
+	}
+
+	return (this._path === other._path && this._type === other._type);
 };
 
 /**
+ * Return the type we're matching against.
  *
- * return the internal path
- * @method path
- *
+ * @returns {undefined|*}
  */
-proto.path = function path(){
-	// File: expression_leaf.h lines: 330-329
-	return this._path;
+proto.getData = function getData() {
+	return this._type;
 };
 
 /**
+ * Return the path associated with the current object.
  *
- * clone this instance to a new one
- * @method shallowClone
- *
+ * @returns {undefined|*|klass._path}
  */
-proto.shallowClone = function shallowClone(){
-	// File: expression_leaf.h lines: 311-314
-	var e = new TypeMatchExpression();
-	e.init( this._path,this._type );
-	return e;
+proto.path = function path() {
+	return this._path;
 };
 

+ 1 - 3
test/lib/pipeline/matcher/ElementPath.js

@@ -4,6 +4,7 @@ var assert = require("assert"),
 
 module.exports = {
 	"ElementPath": {
+		
 		"Should find the item at the path": function() {
 			var p = new ElementPath(),
 				doc = {"x":4, "a":5},
@@ -136,10 +137,7 @@ module.exports = {
 			};
 			p._matches(doc, null, checker);
 		}
-
-
 	}
 };
 
 if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);
-

+ 51 - 0
test/lib/pipeline/matcher/FalseMatchExpression.js

@@ -0,0 +1,51 @@
+"use strict";
+var assert = require("assert"),
+	FalseMatchExpression = require("../../../../lib/pipeline/matcher/FalseMatchExpression");
+
+
+module.exports = {
+	"FalseMatchExpression": {
+
+		"Constructor": function (){
+			var e = new FalseMatchExpression();
+			assert.equal(e._matchType, "ALWAYS_FALSE");
+		},
+
+		"DebugString": function () {
+			var e = new FalseMatchExpression();
+			assert.equal(e.debugString(0), "$false\n");
+		},
+
+		"Equivalent": function () {
+			var a = new FalseMatchExpression(),
+				b = new FalseMatchExpression();
+			assert.equal(a.equivalent(b), true);
+		},
+
+		"Matches": function () {
+			var e = new FalseMatchExpression();
+			assert.equal(e.matches({},{}), false);
+		},
+
+		"MatchesSingleElement": function () {
+			var e = new FalseMatchExpression();
+			assert.equal(e.matchesSingleElement({}), false);
+		},
+
+		"ShallowClone": function () {
+			var e = new FalseMatchExpression();
+			assert.deepEqual(e.shallowClone(), new FalseMatchExpression());
+		},
+
+		"toJson": function () {
+			var e = new FalseMatchExpression(),
+				obj = {};
+			assert.deepEqual(e.toJson(obj), {"$false":1});
+		}
+
+	}
+
+};
+
+if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);
+

+ 72 - 76
test/lib/pipeline/matcher/TypeMatchExpression.js

@@ -5,120 +5,116 @@ var assert = require("assert"),
 
 
 module.exports = {
-	"TypeMatchExpression": {
-		"should match string type": function (){
+	'TypeMatchExpression': {
+		'Should match string type.': function () {
 			var e = new TypeMatchExpression();
-			var s = e.init('', 2 );
 
-			assert.strictEqual(s.code, 'OK');
-			assert.ok( e.matches('abc') );
-			assert.ok( ! e.matches(2) );
+			assert.strictEqual(e.init('', 2).code, 'OK');
 
+			assert.ok(e.matches('abc'));
+			assert.ok(! e.matches(2));
 		},
-		"should match null type": function() {
+
+		'Should match null type.': function () {
 			var e = new TypeMatchExpression();
-			var s = e.init('',10 );
 
-			assert.strictEqual(s.code, 'OK');
-			assert.ok( e.matches(null) );
-			assert.ok( ! e.matches(10) );
+			assert.strictEqual(e.init('', 10).code, 'OK');
 
+			assert.ok(e.matches(null));
+			assert.ok(!e.matches(10));
 		},
-		"should match unknown type": function() {
+
+		'Should match unknown type.': function () {
 			var e = new TypeMatchExpression();
-			var s = e.init('', 1024);
-	
-			assert.strictEqual(s.code, 'OK');
-			assert.ok( ! e.matches(1024) );
-			assert.ok( ! e.matches('abc') );
 
+			assert.strictEqual(e.init('', 1024).code, 'OK');
+
+			assert.ok(!e.matches(1024));
+			assert.ok(!e.matches('abc'));
 		},
-		"should match bool type": function() {
+
+		'Should match bool type.': function () {
 			var e = new TypeMatchExpression();
-			var s = e.init('',8 );
 
-			assert.strictEqual(s.code, 'OK');
-			assert.ok( e.matches(true) );
-			assert.ok( ! e.matches(8) );
+			assert.strictEqual(e.init('', 8).code, 'OK');
 
+			assert.ok(e.matches(true));
+			assert.ok(!e.matches(8));
 		},
-		"should match number type": function() {
+
+		'Should match number type.': function () {
 			var e = new TypeMatchExpression();
 			var s = e.init('a',1 );
 
-			assert.strictEqual(s.code, 'OK');
-			assert.ok( e.matches({'a':[4]}) );	
-			assert.ok( e.matches({'a':[4, 'a']}) );	
-			assert.ok( e.matches({'a':['a', 4]}) );
-			assert.ok( ! e.matches({'a':['a']}) );
-			assert.ok( ! e.matches({'a':[[4]]}) );
+			assert.strictEqual(e.init('a', 1).code, 'OK');
+
+			assert.ok(e.matches({'a':[4]}));
+			assert.ok(e.matches({'a':[4, 'a']}));
+			assert.ok(e.matches({'a':['a', 4]}));
+			assert.ok(!e.matches({'a':['a']}));
+			assert.ok(!e.matches({'a':[[4]]}));
 
 		},
-		"should match array type": function() {
+
+		'Should match array type.': function () {
 			var e = new TypeMatchExpression();
-			var s = e.init('a', 4);
-		
-			assert.strictEqual(s.code, 'OK');
-			assert.ok( ! e.matches({'a':[]}) );	
-			//assert.ok( ! e.matches({'a':[4, 'a']}) );
-			assert.ok( e.matches({'a':[[2]]}) );
-			assert.ok( ! e.matches({'a':'bar'}) );
 
+			assert.strictEqual(e.init('a', 4).code, 'OK');
+
+			assert.ok(!e.matches({a: []}));
+			assert.ok(e.matches({a: [[2]]}));
+			assert.ok(!e.matches({a: 'bar'}));
 		},
-		"should match null type more": function() {
+
+		'Should match null type expanded.': function () {
 			var e = new TypeMatchExpression();
-			var s = e.init('a', 10);
 
-			assert.strictEqual(s.code, 'OK');
-			assert.ok( e.matches({'a':null}) );
-			assert.ok( ! e.matches({'a':4}) );
-			assert.ok( ! e.matches({}));
+			assert.strictEqual(e.init('a', 10).code, 'OK');
+
+			assert.ok(e.matches({a: null}));
+			assert.ok(!e.matches({a: 4}));
+			assert.ok(!e.matches({}));
 
 		},
-		"should match and preserve elemMatchKey": function() {
-			var e = new TypeMatchExpression();
-			var s = e.init('a.b', 2);
-			var m = new MatchDetails();
+
+		'Should match and preserve elemMatchKey.': function () {
+			var e = new TypeMatchExpression(),
+				m = new MatchDetails();
+
 			m.requestElemMatchKey();
 
-			assert.strictEqual(s.code, 'OK');
+			assert.strictEqual(e.init('a.b', 2).code, 'OK');
 			
-			assert.ok( ! e.matches({'a':1}, m) );
-			assert.ok( ! m.hasElemMatchKey() );
+			assert.ok(!e.matches({a: 1}, m));
+			assert.ok(!m.hasElemMatchKey());
 			
-			assert.ok( e.matches({'a':{'b':'string'}},m) );
-			assert.ok( ! m.hasElemMatchKey() );
+			assert.ok(e.matches({a: {b: 'string'}}, m));
+			assert.ok(!m.hasElemMatchKey());
 			
-			assert.ok( e.matches({'a':{'b':['string']}},m) );
-			assert.ok( m.hasElemMatchKey() );
-			assert.strictEqual('0', m.elemMatchKey() );
+			assert.ok(e.matches({a: {b: ['string']}}, m));
+			assert.ok(m.hasElemMatchKey());
+			assert.strictEqual('0', m.elemMatchKey());
 
-	
-			assert.ok( e.matches({'a':[2, {'b':['string']}]},m) );
-			assert.ok( m.hasElemMatchKey() );
-			assert.strictEqual('1', m.elemMatchKey() );
+			assert.ok(e.matches({a: [2, {b: ['string']}]}, m));
+			assert.ok(m.hasElemMatchKey());
 
+			assert.strictEqual('1', m.elemMatchKey());
+		},
 
+		'Should be equivalent.': function() {
+			var a = new TypeMatchExpression(),
+				b = new TypeMatchExpression(),
+				c = new TypeMatchExpression();
 
-		},
-		"should be equivalent": function() {
-			var e = new TypeMatchExpression();
-			var s = e.init('a', 2);
-			var b = new TypeMatchExpression();
-			var c = new TypeMatchExpression();
-
-			assert.strictEqual(s.code, 'OK');
-			s = b.init('a', 1);	
-			assert.strictEqual(s.code, 'OK');
-			s = c.init('b', 2);
-			assert.strictEqual(s.code, 'OK');
-			assert.ok( e.equivalent(e) );
-			assert.ok( !e.equivalent(b) );
-			assert.ok( !e.equivalent(c) );
-		}
+			assert.strictEqual(a.init('a', 2).code, 'OK');
+			assert.strictEqual(b.init('a', 1).code, 'OK');
+			assert.strictEqual(c.init('b', 2).code, 'OK');
 
+			assert.ok(a.equivalent(a));
+			assert.ok(!a.equivalent(b));
+			assert.ok(!a.equivalent(c));
+		}
 	}
 };
 
 if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);
-