Document.js 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  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. // DEPENDENCIES
  13. var Value = require("./Value");
  14. // STATIC MEMBERS
  15. /**
  16. * Shared "_id"
  17. * @static
  18. * @property ID_PROPERTY_NAME
  19. **/
  20. klass.ID_PROPERTY_NAME = "_id";
  21. /**
  22. * Compare two documents.
  23. *
  24. * BSON document field order is significant, so this just goes through the fields in order.
  25. * 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.
  26. *
  27. * @static
  28. * @method compare
  29. * @param rL left document
  30. * @param rR right document
  31. * @returns an integer less than zero, zero, or an integer greater than zero, depending on whether rL < rR, rL == rR, or rL > rR
  32. **/
  33. klass.compare = function compare(l, r){ //TODO: might be able to replace this with a straight compare of docs using JSON.stringify()
  34. var lPropNames = Object.getOwnPropertyNames(l),
  35. lPropNamesLength = lPropNames.length,
  36. rPropNames = Object.getOwnPropertyNames(r),
  37. rPropNamesLength = rPropNames.length;
  38. for(var i = 0; true; ++i) {
  39. if (i >= lPropNamesLength) {
  40. if (i >= rPropNamesLength) return 0; // documents are the same length
  41. return -1; // left document is shorter
  42. }
  43. if (i >= rPropNamesLength) return 1; // right document is shorter
  44. var nameCmp = Value.compare(lPropNames[i], rPropNames[i]);
  45. if (nameCmp !== 0) return nameCmp; // field names are unequal
  46. var valueCmp = Value.compare(l[lPropNames[i]], r[rPropNames[i]]);
  47. if (valueCmp) return valueCmp; // fields are unequal
  48. }
  49. /* NOTREACHED */
  50. throw new Error("This should never happen"); //verify(false)
  51. // return 0;
  52. };
  53. /**
  54. * Clone a document
  55. * @static
  56. * @method clone
  57. * @param document
  58. **/
  59. klass.clone = function(document){
  60. var obj = {};
  61. for(var key in document){
  62. if(document.hasOwnProperty(key)){
  63. var withObjVal = document[key];
  64. if(withObjVal === null) { // necessary to handle null values without failing
  65. obj[key] = withObjVal;
  66. }
  67. else if(withObjVal.constructor === Object){
  68. obj[key] = Document.clone(withObjVal);
  69. }else{
  70. obj[key] = withObjVal;
  71. }
  72. }
  73. }
  74. return obj;
  75. };
  76. // proto.addField = function addField(){ throw new Error("Instead of `Document#addField(key,val)` you should just use `obj[key] = val`"); }
  77. // proto.setField = function addField(){ throw new Error("Instead of `Document#setField(key,val)` you should just use `obj[key] = val`"); }
  78. // proto.getField = function getField(){ throw new Error("Instead of `Document#getField(key)` you should just use `var val = obj[key];`"); }