Document.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. /**
  14. * Shared "_id"
  15. * @static
  16. * @property ID_PROPERTY_NAME
  17. **/
  18. klass.ID_PROPERTY_NAME = "_id";
  19. //SKIPPED: DocumentStorage
  20. /**
  21. * Return JSON representation of this Document
  22. * @method toJson
  23. * @returns {Object} JSON representation of this Document
  24. **/
  25. klass.toJson = function toJson(doc) {
  26. return JSON.parse(JSON.stringify(doc));
  27. };
  28. //SKIPPED: metaFieldTextScore
  29. //SKIPPED: toBsonWithMetaData
  30. //SKIPPED: fromBsonWithMetaData
  31. //SKIPPED: most of MutableDocument except for getNestedField and setNestedField, squashed into Document here (because that's how they use it)
  32. function getNestedFieldHelper(obj, path) {
  33. // NOTE: DEVIATION FROM MONGO: from MutableDocument, implemented a bit differently here but should be same basic functionality
  34. var paths = Array.isArray(path) ? path : path.split(".");
  35. for (var i = 0, l = paths.length, o = obj; i < l && o instanceof Object; i++) {
  36. o = o[paths[i]];
  37. }
  38. return o;
  39. };
  40. klass.getNestedField = klass.getNestedFieldHelper; // NOTE: due to ours being static these are the same
  41. klass.setNestedField = function setNestedField(obj, path, val) {
  42. // NOTE: DEVIATION FROM MONGO: from MutableDocument, implemented a bit differently here but should be same basic functionality
  43. var paths = Array.isArray(path) ? path : path.split("."),
  44. key = paths.pop(),
  45. parent = klass.getNestedField(obj, paths);
  46. if (parent) parent[key] = val;
  47. };
  48. //SKIPPED: getApproximateSize -- not implementing mem usage right now
  49. //SKIPPED: hash_combine
  50. /** Compare two documents.
  51. *
  52. * BSON document field order is significant, so this just goes through
  53. * the fields in order. The comparison is done in roughly the same way
  54. * as strings are compared, but comparing one field at a time instead
  55. * of one character at a time.
  56. *
  57. * Note: This does not consider metadata when comparing documents.
  58. *
  59. * @method compare
  60. * @static
  61. * @param l {Object} left document
  62. * @param r {Object} right document
  63. * @returns an integer less than zero, zero, or an integer greater than
  64. * zero, depending on whether lhs < rhs, lhs == rhs, or lhs > rhs
  65. * Warning: may return values other than -1, 0, or 1
  66. */
  67. klass.compare = function compare(l, r){ //TODO: might be able to replace this with a straight compare of docs using JSON.stringify()
  68. var lPropNames = Object.getOwnPropertyNames(l),
  69. lPropNamesLength = lPropNames.length,
  70. rPropNames = Object.getOwnPropertyNames(r),
  71. rPropNamesLength = rPropNames.length;
  72. for(var i = 0; true; ++i) {
  73. if (i >= lPropNamesLength) {
  74. if (i >= rPropNamesLength) return 0; // documents are the same length
  75. return -1; // left document is shorter
  76. }
  77. if (i >= rPropNamesLength) return 1; // right document is shorter
  78. var rField = rPropNames[i],
  79. lField = lPropNames[i];
  80. var nameCmp = Value.compare(lField, rField);
  81. if (nameCmp !== 0) return nameCmp; // field names are unequal
  82. var valueCmp = Value.compare(l[lPropNames[i]], r[rField]);
  83. if (valueCmp) return valueCmp; // fields are unequal
  84. }
  85. };
  86. //SKIPPED: toString
  87. klass.serializeForSorter = function serializeForSorter(doc) {
  88. //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
  89. return JSON.stringify(doc);
  90. };
  91. klass.deserializeForSorter = function deserializeForSorter(docStr, sorterDeserializeSettings) {
  92. JSON.parse(docStr);
  93. };
  94. //SKIPPED: swap
  95. //SKIPPED: []
  96. //SKIPPED: getField -- inline as: obj[key]
  97. //SKIPPED: getNestedField -- use fieldPath? might need to implement this...
  98. //SKIPPED: size -- need this? Number of fields in this document. O(n) -- recursive
  99. klass.empty = function(obj) {
  100. return Object.keys(obj).length === 0;
  101. };
  102. //SKIPPED: operator <<
  103. //SKIPPED: positionOf
  104. /**
  105. * Clone a document
  106. * @static
  107. * @method clone
  108. * @param doc
  109. */
  110. klass.clone = function clone(doc) {
  111. var obj = {};
  112. for (var key in doc) {
  113. if (doc.hasOwnProperty(key)) {
  114. var val = doc[key];
  115. if (val === undefined || val === null) { // necessary to handle null values without failing
  116. obj[key] = val;
  117. } else if (val instanceof Object && val.constructor === Object) {
  118. obj[key] = Document.clone(val);
  119. } else {
  120. obj[key] = val;
  121. }
  122. }
  123. }
  124. return obj;
  125. };
  126. //SKIPPED: hasTextScore
  127. //SKIPPED: getTextScore
  128. //SKIPPED: memUsageForSorter -- not implementing mem usage right now
  129. //SKIPPED: getOwned -- not implementing mem usage right now
  130. //SKIPPED: getPtr