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