Document.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. "use strict";
  2. /**
  3. * Represents a `Document` (i.e., an `Object`) in `mongo` but in `munge` this is only a set of static helpers since we treat all `Object`s like `Document`s.
  4. * @class Document
  5. * @namespace mungedb-aggregate.pipeline
  6. * @module mungedb-aggregate
  7. * @constructor
  8. **/
  9. var Document = module.exports = function Document(){
  10. if(this.constructor == Document) throw new Error("Never create instances! Use static helpers only.");
  11. }, klass = Document, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  12. var Value = require("./Value"),
  13. FieldPath = require("./FieldPath");
  14. /**
  15. * Shared "_id"
  16. * @static
  17. * @property ID_PROPERTY_NAME
  18. **/
  19. klass.ID_PROPERTY_NAME = "_id";
  20. //SKIPPED: DocumentStorage
  21. /**
  22. * Return JSON representation of this Document
  23. * @method toJson
  24. * @returns {Object} JSON representation of this Document
  25. **/
  26. klass.toJson = function toJson(doc) {
  27. return JSON.parse(JSON.stringify(doc));
  28. };
  29. //SKIPPED: metaFieldTextScore
  30. //SKIPPED: toBsonWithMetaData
  31. //SKIPPED: fromBsonWithMetaData
  32. //SKIPPED: most of MutableDocument except for getNestedField and setNestedField, squashed into Document here (because that's how they use it)
  33. function getNestedFieldHelper(obj, path) {
  34. // NOTE: DEVIATION FROM MONGO: from MutableDocument; similar but necessarily different
  35. var keys = Array.isArray(path) ? path : (path instanceof FieldPath ? path.fieldNames : path.split(".")),
  36. lastKey = keys[keys.length - 1];
  37. for (var i = 0, l = keys.length - 1, cur = obj; i < l && cur instanceof Object; i++) {
  38. var next = cur[keys[i]];
  39. if (!(next instanceof Object)) return undefined;
  40. cur = next;
  41. }
  42. return cur[lastKey];
  43. }
  44. klass.getNestedField = getNestedFieldHelper; // NOTE: ours is static so these are the same
  45. klass.setNestedField = function setNestedField(obj, path, val) {
  46. // NOTE: DEVIATION FROM MONGO: from MutableDocument; similar but necessarily different
  47. var keys = Array.isArray(path) ? path : (path instanceof FieldPath ? path.fieldNames : path.split(".")),
  48. lastKey = keys[keys.length - 1];
  49. for (var i = 0, l = keys.length - 1, cur = obj; i < l && cur instanceof Object; i++) {
  50. var next = cur[keys[i]];
  51. if (!(next instanceof Object)) cur[keys[i]] = next = {};
  52. cur = next;
  53. }
  54. cur[lastKey] = val;
  55. return val;
  56. };
  57. //SKIPPED: getApproximateSize -- not implementing mem usage right now
  58. //SKIPPED: hash_combine
  59. /** Compare two documents.
  60. *
  61. * BSON document field order is significant, so this just goes through
  62. * the fields in order. The comparison is done in roughly the same way
  63. * as strings are compared, but comparing one field at a time instead
  64. * of one character at a time.
  65. *
  66. * Note: This does not consider metadata when comparing documents.
  67. *
  68. * @method compare
  69. * @static
  70. * @param l {Object} left document
  71. * @param r {Object} right document
  72. * @returns an integer less than zero, zero, or an integer greater than
  73. * zero, depending on whether lhs < rhs, lhs == rhs, or lhs > rhs
  74. * Warning: may return values other than -1, 0, or 1
  75. */
  76. klass.compare = function compare(l, r){ //TODO: might be able to replace this with a straight compare of docs using JSON.stringify()
  77. var lPropNames = Object.getOwnPropertyNames(l),
  78. lPropNamesLength = lPropNames.length,
  79. rPropNames = Object.getOwnPropertyNames(r),
  80. rPropNamesLength = rPropNames.length;
  81. for(var i = 0; true; ++i) {
  82. if (i >= lPropNamesLength) {
  83. if (i >= rPropNamesLength) return 0; // documents are the same length
  84. return -1; // left document is shorter
  85. }
  86. if (i >= rPropNamesLength) return 1; // right document is shorter
  87. var rField = rPropNames[i],
  88. lField = lPropNames[i];
  89. var nameCmp = Value.compare(lField, rField);
  90. if (nameCmp !== 0) return nameCmp; // field names are unequal
  91. var valueCmp = Value.compare(l[lPropNames[i]], r[rField]);
  92. if (valueCmp) return valueCmp; // fields are unequal
  93. }
  94. };
  95. //SKIPPED: toString
  96. klass.serializeForSorter = function serializeForSorter(doc) {
  97. //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
  98. return JSON.stringify(doc);
  99. };
  100. klass.deserializeForSorter = function deserializeForSorter(docStr, sorterDeserializeSettings) {
  101. return JSON.parse(docStr);
  102. };
  103. //SKIPPED: swap
  104. //SKIPPED: []
  105. //SKIPPED: getField -- inline as: obj[key]
  106. //SKIPPED: getNestedField -- use fieldPath? might need to implement this...
  107. //SKIPPED: size -- need this? Number of fields in this document. O(n) -- recursive
  108. klass.empty = function(obj) {
  109. return Object.keys(obj).length === 0;
  110. };
  111. //SKIPPED: operator <<
  112. //SKIPPED: positionOf
  113. /**
  114. * Clone a document
  115. * This should only be called by MutableDocument and tests
  116. * The new document shares all the fields' values with the original.
  117. * This is not a deep copy. Only the fields on the top-level document
  118. * are cloned.
  119. * @static
  120. * @method clone
  121. * @param doc
  122. */
  123. klass.clone = function clone(doc) {
  124. var obj = {};
  125. for (var key in doc) {
  126. if (doc.hasOwnProperty(key)) {
  127. obj[key] = doc[key];
  128. }
  129. }
  130. return obj;
  131. };
  132. klass.cloneDeep = function cloneDeep(doc) { //there are casese this is actually what we want
  133. var obj = {};
  134. for (var key in doc) {
  135. if (doc.hasOwnProperty(key)) {
  136. var val = doc[key];
  137. obj[key] = val instanceof Object && val.constructor === Object ? Document.clone(val) : val;
  138. }
  139. }
  140. return obj;
  141. };
  142. //SKIPPED: hasTextScore
  143. //SKIPPED: getTextScore
  144. //SKIPPED: memUsageForSorter -- not implementing mem usage right now
  145. //SKIPPED: getOwned -- not implementing mem usage right now
  146. //SKIPPED: getPtr