Browse Source

Merge branch 'feature/mongo_2.6.5_expressions' into feature/mongo_2.6.5_expressions_Date

Jason Walton 11 years ago
parent
commit
0e045290ae
2 changed files with 189 additions and 31 deletions
  1. 79 31
      lib/pipeline/Document.js
  2. 110 0
      test/lib/pipeline/Document.js

+ 79 - 31
lib/pipeline/Document.js

@@ -11,10 +11,8 @@ var Document = module.exports = function Document(){
 	if(this.constructor == Document) throw new Error("Never create instances! Use static helpers only.");
 }, klass = Document, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
-// DEPENDENCIES
 var Value = require("./Value");
 
-// STATIC MEMBERS
 /**
  * Shared "_id"
  * @static
@@ -22,18 +20,45 @@ var Value = require("./Value");
  **/
 klass.ID_PROPERTY_NAME = "_id";
 
+//SKIPPED: DocumentStorage
+
 /**
- * Compare two documents.
+ * Return JSON representation of this Document
+ * @method toJson
+ * @returns {Object} JSON representation of this Document
+ **/
+klass.toJson = function toJson(doc) {
+ 	return JSON.parse(JSON.stringify(doc));
+};
+
+//SKIPPED: metaFieldTextScore
+//SKIPPED: toBsonWithMetaData
+//SKIPPED: fromBsonWithMetaData
+
+//SKIPPED: MutableDocument
+
+//SKIPPED: getNestedFieldHelper
+//SKIPPED: getNestedField -- same as getNestedFieldHelper in our code
+//SKIPPED: getApproximateSize -- not implementing mem usage right now
+//SKIPPED: hash_combine
+
+/** Compare two documents.
  *
- * BSON document field order is significant, so this just goes through the fields in order.
- * The comparison is done in roughly the same way as strings are compared, but comparing one field at a time instead of one character at a time.
+ *  BSON document field order is significant, so this just goes through
+ *  the fields in order.  The comparison is done in roughly the same way
+ *  as strings are compared, but comparing one field at a time instead
+ *  of one character at a time.
+ *
+ *  Note: This does not consider metadata when comparing documents.
  *
- * @static
  * @method compare
- * @param rL left document
- * @param rR right document
- * @returns an integer less than zero, zero, or an integer greater than zero, depending on whether rL < rR, rL == rR, or rL > rR
- **/
+ * @static
+ * @param l {Object}  left document
+ * @param r {Object} right document
+ * @returns an integer less than zero, zero, or an integer greater than
+ *           zero, depending on whether lhs < rhs, lhs == rhs, or lhs > rhs
+ *  Warning: may return values other than -1, 0, or 1
+ */
 klass.compare = function compare(l, r){	//TODO: might be able to replace this with a straight compare of docs using JSON.stringify()
 	var lPropNames = Object.getOwnPropertyNames(l),
 		lPropNamesLength = lPropNames.length,
@@ -48,42 +73,65 @@ klass.compare = function compare(l, r){	//TODO: might be able to replace this wi
 
 		if (i >= rPropNamesLength) return 1; // right document is shorter
 
-		var nameCmp = Value.compare(lPropNames[i], rPropNames[i]);
+		var rField = rPropNames[i],
+			lField = lPropNames[i];
+		var nameCmp = Value.compare(lField, rField);
 		if (nameCmp !== 0) return nameCmp; // field names are unequal
 
-		var valueCmp = Value.compare(l[lPropNames[i]], r[rPropNames[i]]);
+		var valueCmp = Value.compare(l[lPropNames[i]], r[rField]);
 		if (valueCmp) return valueCmp; // fields are unequal
 	}
+};
+
+//SKIPPED: toString
+
+klass.serializeForSorter = function serializeForSorter(doc) {
+	//NOTE: DEVIATION FROM MONGO: they take a buffer to output the current instance into, ours is static and takes a doc and returns the serialized output
+	return JSON.stringify(doc);
+};
+
+klass.deserializeForSorter = function deserializeForSorter(docStr, sorterDeserializeSettings) {
+	JSON.parse(docStr);
+};
 
-	/* NOTREACHED */
-	throw new Error("This should never happen");	//verify(false)
-//		return 0;
+//SKIPPED: swap
+//SKIPPED: []
+//SKIPPED: getField -- inline as:  obj[key]
+//SKIPPED: getNestedField -- use fieldPath? might need to implement this...
+//SKIPPED: size -- need this? Number of fields in this document. O(n) -- recursive
+klass.empty = function(obj) {
+	return Object.keys(obj).length === 0;
 };
+//SKIPPED: operator <<
+//SKIPPED: positionOf
 
 /**
  * Clone a document
  * @static
  * @method clone
- * @param document
- **/
-klass.clone = function(document){
+ * @param doc
+ */
+klass.clone = function clone(doc) {
 	var obj = {};
-	for(var key in document){
-		if(document.hasOwnProperty(key)){
-			var withObjVal = document[key];
-			if(withObjVal === null) { // necessary to handle null values without failing
-				obj[key] = withObjVal;
-			}
-			else if(withObjVal.constructor === Object){
-				obj[key] = Document.clone(withObjVal);
-			}else{
-				obj[key] = withObjVal;
+	for (var key in doc) {
+		if (doc.hasOwnProperty(key)) {
+			var val = doc[key];
+			if (val === undefined || val === null) { // necessary to handle null values without failing
+				obj[key] = val;
+			} else if (val instanceof Object && val.constructor === Object) {
+				obj[key] = Document.clone(val);
+			} else {
+				obj[key] = val;
 			}
 		}
 	}
 	return obj;
 };
 
-//	proto.addField = function addField(){ throw new Error("Instead of `Document#addField(key,val)` you should just use `obj[key] = val`"); }
-//	proto.setField = function addField(){ throw new Error("Instead of `Document#setField(key,val)` you should just use `obj[key] = val`"); }
-//  proto.getField = function getField(){ throw new Error("Instead of `Document#getField(key)` you should just use `var val = obj[key];`"); }
+//SKIPPED: hasTextScore
+//SKIPPED: getTextScore
+
+//SKIPPED: memUsageForSorter -- not implementing mem usage right now
+//SKIPPED: getOwned -- not implementing mem usage right now
+
+//SKIPPED: getPtr

+ 110 - 0
test/lib/pipeline/Document.js

@@ -0,0 +1,110 @@
+"use strict";
+var assert = require("assert"),
+	Document = require("../../../lib/pipeline/Document");
+
+// Mocha one-liner to make these tests self-hosted
+if(!module.parent)return(require.cache[__filename]=null,(new(require("mocha"))({ui:"exports",reporter:"spec",grep:process.env.TEST_GREP})).addFile(__filename).run(process.exit));
+
+exports.Document = {
+
+	"Json conversion": {
+
+		"convert to Json": function toJson() {
+			var aDocument = {"prop1":0},
+				result = Document.toJson(aDocument);
+			assert.equal(result, '{"prop1":0}');
+		},
+
+		"convert to Json with metadata": function toJsonWithMetaData() {
+			var aDocument = {"prop1": 0,"metadata":"stuff"},
+				result = Document.toJsonWithMetaData(aDocument);
+			assert.equal(result, '{"prop1":0,"metadata":"stuff"}');
+		},
+
+		"convert from Json": function fromJsonWithMetaData() {
+			var aDocumentString = '{\"prop1\":0,\"metadata\":1}',
+				jsonDocument = {"prop1":0,"metadata":1},
+				result = Document.fromJsonWithMetaData(aDocumentString);
+			assert.deepEqual(result, jsonDocument);
+		},
+
+	},
+
+	"compare 2 Documents": {
+
+		"should return 0 if Documents are identical": function compareDocumentsIdentical() {
+			var lDocument = {"prop1": 0},
+				rDocument = {"prop1": 0},
+				result = Document.compare(lDocument, rDocument);
+			assert.equal(result, 0);
+		},
+
+		"should return -1 if left Document is shorter": function compareLeftDocumentShorter() {
+			var lDocument = {"prop1": 0},
+				rDocument = {"prop1": 0, "prop2": 0},
+				result = Document.compare(lDocument, rDocument);
+			assert.equal(result, -1);
+		},
+
+		"should return 1 if right Document is shorter": function compareRightDocumentShorter() {
+			var lDocument = {"prop1": 0, "prop2": 0},
+				rDocument = {"prop1": 0},
+				result = Document.compare(lDocument, rDocument);
+			assert.equal(result, 1);
+		},
+
+		"should return nameCmp result -1 if left Document field value is less": function compareLeftDocumentFieldLess() {
+			var lDocument = {"prop1": 0},
+				rDocument = {"prop1": 1},
+				result = Document.compare(lDocument, rDocument);
+			assert.equal(result, -1);
+		},
+
+		"should return nameCmp result 1 if right Document field value is less": function compareRightDocumentFieldLess() {
+			var lDocument = {"prop1": 1},
+				rDocument = {"prop1": 0},
+				result = Document.compare(lDocument, rDocument);
+			assert.equal(result, 1);
+		},
+
+	},
+
+	"clone a Document": {
+
+		"should return same field and value from cloned Document ": function clonedDocumentSingleFieldValue() {
+			var doc = {"prop1": 17},
+				res = Document.clone(doc);
+			assert(res instanceof Object);
+			assert.deepEqual(doc, res);
+			assert.equal(res.prop1, 17);
+		},
+
+		"should return same fields and values from cloned Document ": function clonedDocumentMultiFieldValue() {
+			var doc = {"prop1": 17, "prop2": "a string"},
+				res = Document.clone(doc);
+			assert.deepEqual(doc, res);
+			assert(res instanceof Object);
+			assert.equal(res.prop1, 17);
+			assert.equal(res.prop2, "a string");
+		},
+
+	},
+
+	"serialize and deserialize for sorter": {
+
+		"should return a string": function serializeDocument() {
+			var doc = {"prop1":1},
+				res = Document.serializeForSorter(doc);
+			assert.equal(res, "{\"prop1\":1}");
+		},
+
+		"should return a Document": function deserializeToDocument() {
+			var str = "{\"prop1\":1}",
+				doc = {"prop1":1},
+				res = Document.deserializeForSorter(str);
+			assert.deepEqual(res, doc);
+		},
+
+	},
+
+};