collection.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*!
  2. * Module dependencies.
  3. */
  4. var MongooseCollection = require('../../collection')
  5. , Collection = require('mongodb').Collection
  6. , STATES = require('../../connectionstate')
  7. , utils = require('../../utils')
  8. /**
  9. * A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) collection implementation.
  10. *
  11. * All methods methods from the [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver are copied and wrapped in queue management.
  12. *
  13. * @inherits Collection
  14. * @api private
  15. */
  16. function NativeCollection () {
  17. this.collection = null;
  18. MongooseCollection.apply(this, arguments);
  19. }
  20. /*!
  21. * Inherit from abstract Collection.
  22. */
  23. NativeCollection.prototype.__proto__ = MongooseCollection.prototype;
  24. /**
  25. * Called when the connection opens.
  26. *
  27. * @api private
  28. */
  29. NativeCollection.prototype.onOpen = function () {
  30. var self = this;
  31. // always get a new collection in case the user changed host:port
  32. // of parent db instance when re-opening the connection.
  33. if (!self.opts.capped.size) {
  34. // non-capped
  35. return self.conn.db.collection(self.name, callback);
  36. }
  37. // capped
  38. return self.conn.db.collection(self.name, function (err, c) {
  39. if (err) return callback(err);
  40. // discover if this collection exists and if it is capped
  41. self.conn.db.listCollections({ name: self.name }).toArray(function(err, docs) {
  42. if (err) {
  43. return callback(err);
  44. }
  45. var doc = docs[0];
  46. var exists = !!doc;
  47. if (exists) {
  48. if (doc.options && doc.options.capped) {
  49. callback(null, c);
  50. } else {
  51. var msg = 'A non-capped collection exists with the name: '+ self.name +'\n\n'
  52. + ' To use this collection as a capped collection, please '
  53. + 'first convert it.\n'
  54. + ' http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-Convertingacollectiontocapped'
  55. err = new Error(msg);
  56. callback(err);
  57. }
  58. } else {
  59. // create
  60. var opts = utils.clone(self.opts.capped);
  61. opts.capped = true;
  62. self.conn.db.createCollection(self.name, opts, callback);
  63. }
  64. });
  65. });
  66. function callback (err, collection) {
  67. if (err) {
  68. // likely a strict mode error
  69. self.conn.emit('error', err);
  70. } else {
  71. self.collection = collection;
  72. MongooseCollection.prototype.onOpen.call(self);
  73. }
  74. };
  75. };
  76. /**
  77. * Called when the connection closes
  78. *
  79. * @api private
  80. */
  81. NativeCollection.prototype.onClose = function () {
  82. MongooseCollection.prototype.onClose.call(this);
  83. };
  84. /*!
  85. * Copy the collection methods and make them subject to queues
  86. */
  87. for (var i in Collection.prototype) {
  88. // Janky hack to work around gh-3005 until we can get rid of the mongoose
  89. // collection abstraction
  90. try {
  91. if (typeof Collection.prototype[i] !== 'function') {
  92. continue;
  93. }
  94. } catch(e) {
  95. continue;
  96. }
  97. (function(i){
  98. NativeCollection.prototype[i] = function () {
  99. if (this.buffer) {
  100. this.addQueue(i, arguments);
  101. return;
  102. }
  103. var collection = this.collection
  104. , args = arguments
  105. , self = this
  106. , debug = self.conn.base.options.debug;
  107. if (debug) {
  108. if ('function' === typeof debug) {
  109. debug.apply(debug
  110. , [self.name, i].concat(utils.args(args, 0, args.length-1)));
  111. } else {
  112. console.error('\x1B[0;36mMongoose:\x1B[0m %s.%s(%s) %s %s %s'
  113. , self.name
  114. , i
  115. , print(args[0])
  116. , print(args[1])
  117. , print(args[2])
  118. , print(args[3]))
  119. }
  120. }
  121. return collection[i].apply(collection, args);
  122. };
  123. })(i);
  124. }
  125. /*!
  126. * Debug print helper
  127. */
  128. function print (arg) {
  129. var type = typeof arg;
  130. if ('function' === type || 'undefined' === type) return '';
  131. return format(arg);
  132. }
  133. /*!
  134. * Debug print helper
  135. */
  136. function format (obj, sub) {
  137. var x = utils.clone(obj, { retainKeyOrder: 1 });
  138. if (x) {
  139. if ('Binary' === x.constructor.name) {
  140. x = '[object Buffer]';
  141. } else if ('ObjectID' === x.constructor.name) {
  142. var representation = 'ObjectId("' + x.toHexString() + '")';
  143. x = { inspect: function() { return representation; } };
  144. } else if ('Date' === x.constructor.name) {
  145. var representation = 'new Date("' + x.toUTCString() + '")';
  146. x = { inspect: function() { return representation; } };
  147. } else if ('Object' === x.constructor.name) {
  148. var keys = Object.keys(x);
  149. var numKeys = keys.length;
  150. var key;
  151. for (var i = 0; i < numKeys; ++i) {
  152. key = keys[i];
  153. if (x[key]) {
  154. if ('Binary' === x[key].constructor.name) {
  155. x[key] = '[object Buffer]';
  156. } else if ('Object' === x[key].constructor.name) {
  157. x[key] = format(x[key], true);
  158. } else if ('ObjectID' === x[key].constructor.name) {
  159. ;(function(x){
  160. var representation = 'ObjectId("' + x[key].toHexString() + '")';
  161. x[key] = { inspect: function() { return representation; } };
  162. })(x)
  163. } else if ('Date' === x[key].constructor.name) {
  164. ;(function(x){
  165. var representation = 'new Date("' + x[key].toUTCString() + '")';
  166. x[key] = { inspect: function() { return representation; } };
  167. })(x)
  168. } else if (Array.isArray(x[key])) {
  169. x[key] = x[key].map(function (o) {
  170. return format(o, true)
  171. });
  172. }
  173. }
  174. }
  175. }
  176. if (sub) return x;
  177. }
  178. return require('util')
  179. .inspect(x, false, 10, true)
  180. .replace(/\n/g, '')
  181. .replace(/\s{2,}/g, ' ')
  182. }
  183. /**
  184. * Retreives information about this collections indexes.
  185. *
  186. * @param {Function} callback
  187. * @method getIndexes
  188. * @api public
  189. */
  190. NativeCollection.prototype.getIndexes = NativeCollection.prototype.indexInformation;
  191. /*!
  192. * Module exports.
  193. */
  194. module.exports = NativeCollection;