mongodb 2.1.0-alpha → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/HISTORY.md +574 -429
  2. package/Makefile +2 -5
  3. package/README.md +108 -15
  4. package/conf.json +17 -13
  5. package/index.js +13 -2
  6. package/lib/admin.js +113 -47
  7. package/lib/aggregation_cursor.js +56 -28
  8. package/lib/apm.js +608 -0
  9. package/lib/bulk/common.js +7 -7
  10. package/lib/bulk/ordered.js +56 -17
  11. package/lib/bulk/unordered.js +52 -14
  12. package/lib/collection.js +671 -212
  13. package/lib/command_cursor.js +60 -32
  14. package/lib/cursor.js +313 -115
  15. package/lib/db.js +264 -105
  16. package/lib/gridfs/chunk.js +26 -29
  17. package/lib/gridfs/grid_store.js +150 -64
  18. package/lib/gridfs-stream/download.js +310 -0
  19. package/lib/gridfs-stream/index.js +335 -0
  20. package/lib/gridfs-stream/upload.js +450 -0
  21. package/lib/metadata.js +64 -0
  22. package/lib/mongo_client.js +69 -39
  23. package/lib/mongos.js +65 -20
  24. package/lib/replset.js +69 -34
  25. package/lib/server.js +35 -1
  26. package/lib/topology_base.js +22 -10
  27. package/lib/url_parser.js +111 -13
  28. package/lib/utils.js +9 -8
  29. package/mongolabs.js +427 -0
  30. package/package.json +8 -6
  31. package/t.js +68 -51
  32. package/test.js +12 -0
  33. package/test_boot/boot.sh +3 -0
  34. package/test_boot/ca.pem +49 -0
  35. package/test_boot/client.pem +48 -0
  36. package/test_boot/client_password.pem +51 -0
  37. package/test_boot/connect.js +29 -0
  38. package/test_boot/data/WiredTiger +2 -0
  39. package/test_boot/data/WiredTiger.lock +1 -0
  40. package/test_boot/data/WiredTiger.turtle +6 -0
  41. package/test_boot/data/WiredTiger.wt +0 -0
  42. package/test_boot/data/WiredTigerLAS.wt +0 -0
  43. package/test_boot/data/_mdb_catalog.wt +0 -0
  44. package/test_boot/data/collection-0-757073248613337118.wt +0 -0
  45. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-44-37Z-00000 +0 -0
  46. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-45-15Z-00000 +0 -0
  47. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-46-31Z-00000 +0 -0
  48. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-47-25Z-00000 +0 -0
  49. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-49-07Z-00000 +0 -0
  50. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-50-41Z-00000 +0 -0
  51. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-50-53Z-00000 +0 -0
  52. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-52-31Z-00000 +0 -0
  53. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-54-53Z-00000 +0 -0
  54. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-55-09Z-00000 +0 -0
  55. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-55-38Z-00000 +0 -0
  56. package/test_boot/data/index-1-757073248613337118.wt +0 -0
  57. package/test_boot/data/mongod.lock +0 -0
  58. package/test_boot/data/sizeStorer.wt +0 -0
  59. package/test_boot/data/storage.bson +0 -0
  60. package/test_boot/server_password.pem +51 -0
  61. package/.travis.yml +0 -10
  62. package/t1.js +0 -59
  63. package/wercker.yml +0 -19
@@ -0,0 +1,310 @@
1
+ var shallowClone = require('../utils').shallowClone;
2
+ var stream = require('stream');
3
+ var util = require('util');
4
+
5
+ module.exports = GridFSBucketReadStream;
6
+
7
+ /**
8
+ * A readable stream that enables you to read buffers from GridFS.
9
+ *
10
+ * Do not instantiate this class directly. Use `openDownloadStream()` instead.
11
+ *
12
+ * @class
13
+ * @param {Collection} chunks Handle for chunks collection
14
+ * @param {Collection} files Handle for files collection
15
+ * @param {Object} readPreference The read preference to use
16
+ * @param {Object} filter The query to use to find the file document
17
+ * @param {Object} [options=null] Optional settings.
18
+ * @param {Number} [options.sort=null] Optional sort for the file find query
19
+ * @param {Number} [options.skip=null] Optional skip for the file find query
20
+ * @param {Number} [options.start=null] Optional 0-based offset in bytes to start streaming from
21
+ * @param {Number} [options.end=null] Optional 0-based offset in bytes to stop streaming before
22
+ * @fires GridFSBucketReadStream#error
23
+ * @fires GridFSBucketReadStream#file
24
+ * @return {GridFSBucketReadStream} a GridFSBucketReadStream instance.
25
+ */
26
+
27
+ function GridFSBucketReadStream(chunks, files, readPreference, filter, options) {
28
+ var _this = this;
29
+ this.s = {
30
+ bytesRead: 0,
31
+ chunks: chunks,
32
+ cursor: null,
33
+ expected: 0,
34
+ files: files,
35
+ filter: filter,
36
+ init: false,
37
+ expectedEnd: 0,
38
+ file: null,
39
+ options: options,
40
+ readPreference: readPreference
41
+ };
42
+
43
+ stream.Readable.call(this);
44
+ }
45
+
46
+ util.inherits(GridFSBucketReadStream, stream.Readable);
47
+
48
+ /**
49
+ * An error occurred
50
+ *
51
+ * @event GridFSBucketReadStream#error
52
+ * @type {Error}
53
+ */
54
+
55
+ /**
56
+ * Fires when the stream loaded the file document corresponding to the
57
+ * provided id.
58
+ *
59
+ * @event GridFSBucketReadStream#file
60
+ * @type {object}
61
+ */
62
+
63
+ /**
64
+ * Reads from the cursor and pushes to the stream.
65
+ * @method
66
+ */
67
+
68
+ GridFSBucketReadStream.prototype._read = function() {
69
+ var _this = this;
70
+ waitForFile(_this, function() {
71
+ doRead(_this);
72
+ });
73
+ };
74
+
75
+ /**
76
+ * Sets the 0-based offset in bytes to start streaming from. Throws
77
+ * an error if this stream has entered flowing mode
78
+ * (e.g. if you've already called `on('data')`)
79
+ * @method
80
+ * @param {Number} start Offset in bytes to start reading at
81
+ * @return {GridFSBucketReadStream}
82
+ */
83
+
84
+ GridFSBucketReadStream.prototype.start = function(start) {
85
+ throwIfInitialized(this);
86
+ this.s.options.start = start;
87
+ return this;
88
+ };
89
+
90
+ /**
91
+ * Sets the 0-based offset in bytes to start streaming from. Throws
92
+ * an error if this stream has entered flowing mode
93
+ * (e.g. if you've already called `on('data')`)
94
+ * @method
95
+ * @param {Number} end Offset in bytes to stop reading at
96
+ * @return {GridFSBucketReadStream}
97
+ */
98
+
99
+ GridFSBucketReadStream.prototype.end = function(end) {
100
+ throwIfInitialized(this);
101
+ this.s.options.end = end;
102
+ return this;
103
+ };
104
+
105
+ /**
106
+ * @ignore
107
+ */
108
+
109
+ function throwIfInitialized(self) {
110
+ if (self.s.init) {
111
+ throw new Error('You cannot change options after the stream has entered' +
112
+ 'flowing mode!');
113
+ }
114
+ }
115
+
116
+ /**
117
+ * @ignore
118
+ */
119
+
120
+ function doRead(_this) {
121
+ _this.s.cursor.next(function(error, doc) {
122
+ if (error) {
123
+ return __handleError(_this, error);
124
+ }
125
+ if (!doc) {
126
+ return _this.push(null);
127
+ }
128
+
129
+ var bytesRemaining = _this.s.file.length - _this.s.bytesRead;
130
+ var expectedN = _this.s.expected++;
131
+ var expectedLength = Math.min(_this.s.file.chunkSize,
132
+ bytesRemaining);
133
+ if (doc.n > expectedN) {
134
+ var errmsg = 'ChunkIsMissing: Got unexpected n: ' + doc.n +
135
+ ', expected: ' + expectedN;
136
+ return __handleError(_this, new Error(errmsg));
137
+ }
138
+ if (doc.n < expectedN) {
139
+ var errmsg = 'ExtraChunk: Got unexpected n: ' + doc.n +
140
+ ', expected: ' + expectedN;
141
+ return __handleError(_this, new Error(errmsg));
142
+ }
143
+ if (doc.data.length() !== expectedLength) {
144
+ if (bytesRemaining <= 0) {
145
+ var errmsg = 'ExtraChunk: Got unexpected n: ' + doc.n;
146
+ return __handleError(_this, new Error(errmsg));
147
+ }
148
+ var errmsg = 'ChunkIsWrongSize: Got unexpected length: ' +
149
+ doc.data.length() + ', expected: ' + expectedLength;
150
+ return __handleError(_this, new Error(errmsg));
151
+ }
152
+
153
+ _this.s.bytesRead += doc.data.length();
154
+
155
+ if (doc.data.buffer.length === 0) {
156
+ return _this.push(null);
157
+ }
158
+
159
+ var sliceStart = null;
160
+ var sliceEnd = null;
161
+ var buf = doc.data.buffer;
162
+ if (_this.s.bytesToSkip != null) {
163
+ sliceStart = _this.s.bytesToSkip;
164
+ _this.s.bytesToSkip = 0;
165
+ }
166
+
167
+ if (expectedN === _this.s.expectedEnd && _this.s.bytesToTrim != null) {
168
+ sliceEnd = _this.s.bytesToTrim;
169
+ }
170
+
171
+ if (sliceStart != null || sliceEnd != null) {
172
+ buf = buf.slice(sliceStart || 0, sliceEnd || buf.length);
173
+ }
174
+
175
+ _this.push(buf);
176
+ });
177
+ };
178
+
179
+ /**
180
+ * @ignore
181
+ */
182
+
183
+ function init(self) {
184
+ var findOneOptions = {};
185
+ if (self.s.readPreference) {
186
+ findOneOptions.readPreference = self.s.readPreference;
187
+ }
188
+ if (self.s.options && self.s.options.sort) {
189
+ findOneOptions.sort = self.s.options.sort;
190
+ }
191
+ if (self.s.options && self.s.options.skip) {
192
+ findOneOptions.skip = self.s.options.skip;
193
+ }
194
+
195
+ self.s.files.findOne(self.s.filter, findOneOptions, function(error, doc) {
196
+ if (error) {
197
+ return __handleError(self, error);
198
+ }
199
+ if (!doc) {
200
+ var identifier = self.s.filter._id ?
201
+ self.s.filter._id.toString() : self.s.filter.filename;
202
+ var errmsg = 'FileNotFound: file ' + identifier + ' was not found';
203
+ return __handleError(self, new Error(errmsg));
204
+ }
205
+
206
+ // If document is empty, kill the stream immediately and don't
207
+ // execute any reads
208
+ if (doc.length <= 0) {
209
+ self.push(null);
210
+ return;
211
+ }
212
+
213
+ self.s.cursor = self.s.chunks.find({ files_id: doc._id }).sort({ n: 1 });
214
+ if (self.s.readPreference) {
215
+ self.s.cursor.setReadPreference(self.s.readPreference);
216
+ }
217
+
218
+ self.s.expectedEnd = Math.ceil(doc.length / doc.chunkSize);
219
+ self.s.file = doc;
220
+ self.s.bytesToSkip = handleStartOption(self, doc, self.s.cursor,
221
+ self.s.options);
222
+ self.s.bytesToTrim = handleEndOption(self, doc, self.s.cursor,
223
+ self.s.options);
224
+ self.emit('file', doc);
225
+ });
226
+ }
227
+
228
+ /**
229
+ * @ignore
230
+ */
231
+
232
+ function waitForFile(_this, callback) {
233
+ if (_this.s.file) {
234
+ return callback();
235
+ }
236
+
237
+ if (!_this.s.init) {
238
+ init(_this);
239
+ _this.s.init = true;
240
+ }
241
+
242
+ _this.once('file', function() {
243
+ callback();
244
+ });
245
+ };
246
+
247
+ /**
248
+ * @ignore
249
+ */
250
+
251
+ function handleStartOption(stream, doc, cursor, options) {
252
+ if (options && options.start != null) {
253
+ if (options.start > doc.length) {
254
+ throw new Error('Stream start (' + options.start + ') must not be ' +
255
+ 'more than the length of the file (' + doc.length +')')
256
+ }
257
+ if (options.start < 0) {
258
+ throw new Error('Stream start (' + options.start + ') must not be ' +
259
+ 'negative');
260
+ }
261
+ if (options.end != null && options.end < options.start) {
262
+ throw new Error('Stream start (' + options.start + ') must not be ' +
263
+ 'greater than stream end (' + options.end + ')');
264
+ }
265
+
266
+ cursor.skip(Math.floor(options.start / doc.chunkSize));
267
+
268
+ stream.s.bytesRead = Math.floor(options.start / doc.chunkSize) *
269
+ doc.chunkSize;
270
+ stream.s.expected = Math.floor(options.start / doc.chunkSize);
271
+
272
+ return options.start - stream.s.bytesRead;
273
+ }
274
+ }
275
+
276
+ /**
277
+ * @ignore
278
+ */
279
+
280
+ function handleEndOption(stream, doc, cursor, options) {
281
+ if (options && options.end != null) {
282
+ if (options.end > doc.length) {
283
+ throw new Error('Stream end (' + options.end + ') must not be ' +
284
+ 'more than the length of the file (' + doc.length +')')
285
+ }
286
+ if (options.start < 0) {
287
+ throw new Error('Stream end (' + options.end + ') must not be ' +
288
+ 'negative');
289
+ }
290
+
291
+ var start = options.start != null ?
292
+ Math.floor(options.start / doc.chunkSize) :
293
+ 0;
294
+
295
+ cursor.limit(Math.ceil(options.end / doc.chunkSize) - start);
296
+
297
+ stream.s.expectedEnd = Math.ceil(options.end / doc.chunkSize);
298
+
299
+ return (Math.ceil(options.end / doc.chunkSize) * doc.chunkSize) -
300
+ options.end;
301
+ }
302
+ }
303
+
304
+ /**
305
+ * @ignore
306
+ */
307
+
308
+ function __handleError(_this, error) {
309
+ _this.emit('error', error);
310
+ }
@@ -0,0 +1,335 @@
1
+ var Emitter = require('events').EventEmitter;
2
+ var GridFSBucketReadStream = require('./download');
3
+ var GridFSBucketWriteStream = require('./upload');
4
+ var shallowClone = require('../utils').shallowClone;
5
+ var toError = require('../utils').toError;
6
+ var util = require('util');
7
+
8
+ var DEFAULT_GRIDFS_BUCKET_OPTIONS = {
9
+ bucketName: 'fs',
10
+ chunkSizeBytes: 255 * 1024
11
+ };
12
+
13
+ module.exports = GridFSBucket;
14
+
15
+ /**
16
+ * Constructor for a streaming GridFS interface
17
+ * @class
18
+ * @param {Db} db A db handle
19
+ * @param {object} [options=null] Optional settings.
20
+ * @param {string} [options.bucketName="fs"] The 'files' and 'chunks' collections will be prefixed with the bucket name followed by a dot.
21
+ * @param {number} [options.chunkSizeBytes=255 * 1024] Number of bytes stored in each chunk. Defaults to 255KB
22
+ * @param {object} [options.writeConcern=null] Optional write concern to be passed to write operations, for instance `{ w: 1 }`
23
+ * @param {object} [options.readPreference=null] Optional read preference to be passed to read operations
24
+ * @fires GridFSBucketWriteStream#index
25
+ * @return {GridFSBucket}
26
+ */
27
+
28
+ function GridFSBucket(db, options) {
29
+ Emitter.apply(this);
30
+ this.setMaxListeners(0);
31
+
32
+ if (options && typeof options === 'object') {
33
+ options = shallowClone(options);
34
+ var keys = Object.keys(DEFAULT_GRIDFS_BUCKET_OPTIONS);
35
+ for (var i = 0; i < keys.length; ++i) {
36
+ if (!options[keys[i]]) {
37
+ options[keys[i]] = DEFAULT_GRIDFS_BUCKET_OPTIONS[keys[i]];
38
+ }
39
+ }
40
+ } else {
41
+ options = DEFAULT_GRIDFS_BUCKET_OPTIONS;
42
+ }
43
+
44
+ this.s = {
45
+ db: db,
46
+ options: options,
47
+ _chunksCollection: db.collection(options.bucketName + '.chunks'),
48
+ _filesCollection: db.collection(options.bucketName + '.files'),
49
+ checkedIndexes: false,
50
+ calledOpenUploadStream: false,
51
+ promiseLibrary: db.s.promiseLibrary ||
52
+ (typeof global.Promise == 'function' ? global.Promise : require('es6-promise').Promise)
53
+ };
54
+ };
55
+
56
+ util.inherits(GridFSBucket, Emitter);
57
+
58
+ /**
59
+ * When the first call to openUploadStream is made, the upload stream will
60
+ * check to see if it needs to create the proper indexes on the chunks and
61
+ * files collections. This event is fired either when 1) it determines that
62
+ * no index creation is necessary, 2) when it successfully creates the
63
+ * necessary indexes.
64
+ *
65
+ * @event GridFSBucket#index
66
+ * @type {Error}
67
+ */
68
+
69
+ /**
70
+ * Returns a writable stream (GridFSBucketWriteStream) for writing
71
+ * buffers to GridFS. The stream's 'id' property contains the resulting
72
+ * file's id.
73
+ * @method
74
+ * @param {string} filename The value of the 'filename' key in the files doc
75
+ * @param {object} [options=null] Optional settings.
76
+ * @param {number} [options.chunkSizeBytes=null] Optional overwrite this bucket's chunkSizeBytes for this file
77
+ * @param {object} [options.metadata=null] Optional object to store in the file document's `metadata` field
78
+ * @param {string} [options.contentType=null] Optional string to store in the file document's `contentType` field
79
+ * @param {array} [options.aliases=null] Optional array of strings to store in the file document's `aliases` field
80
+ * @return {GridFSBucketWriteStream}
81
+ */
82
+
83
+ GridFSBucket.prototype.openUploadStream = function(filename, options) {
84
+ if (options) {
85
+ options = shallowClone(options);
86
+ } else {
87
+ options = {};
88
+ }
89
+ if (!options.chunkSizeBytes) {
90
+ options.chunkSizeBytes = this.s.options.chunkSizeBytes;
91
+ }
92
+ return new GridFSBucketWriteStream(this, filename, options);
93
+ };
94
+
95
+ /**
96
+ * Returns a readable stream (GridFSBucketReadStream) for streaming file
97
+ * data from GridFS.
98
+ * @method
99
+ * @param {ObjectId} id The id of the file doc
100
+ * @param {Object} [options=null] Optional settings.
101
+ * @param {Number} [options.start=null] Optional 0-based offset in bytes to start streaming from
102
+ * @param {Number} [options.end=null] Optional 0-based offset in bytes to stop streaming before
103
+ * @return {GridFSBucketReadStream}
104
+ */
105
+
106
+ GridFSBucket.prototype.openDownloadStream = function(id, options) {
107
+ var filter = { _id: id };
108
+ var options = {
109
+ start: options && options.start,
110
+ end: options && options.end
111
+ };
112
+ return new GridFSBucketReadStream(this.s._chunksCollection,
113
+ this.s._filesCollection, this.s.options.readPreference, filter, options);
114
+ };
115
+
116
+ /**
117
+ * Deletes a file with the given id
118
+ * @method
119
+ * @param {ObjectId} id The id of the file doc
120
+ * @param {Function} callback
121
+ */
122
+
123
+ GridFSBucket.prototype.delete = function(id, callback) {
124
+ if (typeof callback === 'function') {
125
+ return _delete(this, id, callback);
126
+ }
127
+
128
+ var _this = this;
129
+ return new this.s.promiseLibrary(function(resolve, reject) {
130
+ _delete(_this, id, function(error, res) {
131
+ if (error) {
132
+ reject(error);
133
+ } else {
134
+ resolve(res);
135
+ }
136
+ });
137
+ });
138
+ };
139
+
140
+ /**
141
+ * @ignore
142
+ */
143
+
144
+ function _delete(_this, id, callback) {
145
+ _this.s._filesCollection.deleteOne({ _id: id }, function(error, res) {
146
+ if (error) {
147
+ return callback(error);
148
+ }
149
+
150
+ _this.s._chunksCollection.deleteMany({ files_id: id }, function(error) {
151
+ if (error) {
152
+ return callback(error);
153
+ }
154
+
155
+ // Delete orphaned chunks before returning FileNotFound
156
+ if (!res.result.n) {
157
+ var errmsg = 'FileNotFound: no file with id ' + id + ' found';
158
+ return callback(new Error(errmsg));
159
+ }
160
+
161
+ callback();
162
+ });
163
+ });
164
+ }
165
+
166
+ /**
167
+ * Convenience wrapper around find on the files collection
168
+ * @method
169
+ * @param {Object} filter
170
+ * @param {Object} [options=null] Optional settings for cursor
171
+ * @param {number} [options.batchSize=null] Optional batch size for cursor
172
+ * @param {number} [options.limit=null] Optional limit for cursor
173
+ * @param {number} [options.maxTimeMS=null] Optional maxTimeMS for cursor
174
+ * @param {boolean} [options.noCursorTimeout=null] Optionally set cursor's `noCursorTimeout` flag
175
+ * @param {number} [options.skip=null] Optional skip for cursor
176
+ * @param {object} [options.sort=null] Optional sort for cursor
177
+ * @return {Cursor}
178
+ */
179
+
180
+ GridFSBucket.prototype.find = function(filter, options) {
181
+ filter = filter || {};
182
+ options = options || {};
183
+
184
+ var cursor = this.s._filesCollection.find(filter);
185
+
186
+ if (options.batchSize != null) {
187
+ cursor.batchSize(options.batchSize);
188
+ }
189
+ if (options.limit != null) {
190
+ cursor.limit(options.limit);
191
+ }
192
+ if (options.maxTimeMS != null) {
193
+ cursor.maxTimeMS(options.maxTimeMS);
194
+ }
195
+ if (options.noCursorTimeout != null) {
196
+ cursor.addCursorFlag('noCursorTimeout', options.noCursorTimeout);
197
+ }
198
+ if (options.skip != null) {
199
+ cursor.skip(options.skip);
200
+ }
201
+ if (options.sort != null) {
202
+ cursor.sort(options.sort);
203
+ }
204
+
205
+ return cursor;
206
+ };
207
+
208
+ /**
209
+ * Returns a readable stream (GridFSBucketReadStream) for streaming the
210
+ * file with the given name from GridFS. If there are multiple files with
211
+ * the same name, this will stream the most recent file with the given name
212
+ * (as determined by the `uploadedDate` field). You can set the `revision`
213
+ * option to change this behavior.
214
+ * @method
215
+ * @param {String} filename The name of the file to stream
216
+ * @param {Object} [options=null] Optional settings
217
+ * @param {number} [options.revision=-1] The revision number relative to the oldest file with the given filename. 0 gets you the oldest file, 1 gets you the 2nd oldest, -1 gets you the newest.
218
+ * @param {Number} [options.start=null] Optional 0-based offset in bytes to start streaming from
219
+ * @param {Number} [options.end=null] Optional 0-based offset in bytes to stop streaming before
220
+ * @return {GridFSBucketReadStream}
221
+ */
222
+
223
+ GridFSBucket.prototype.openDownloadStreamByName = function(filename, options) {
224
+ var sort = { uploadedDate: -1 };
225
+ var skip = null;
226
+ if (options && options.revision != null) {
227
+ if (options.revision >= 0) {
228
+ sort = { uploadedDate: 1 };
229
+ skip = options.revision;
230
+ } else {
231
+ skip = -options.revision - 1;
232
+ }
233
+ }
234
+
235
+ var filter = { filename: filename };
236
+ var options = {
237
+ sort: sort,
238
+ skip: skip,
239
+ start: options && options.start,
240
+ end: options && options.end
241
+ };
242
+ return new GridFSBucketReadStream(this.s._chunksCollection,
243
+ this.s._filesCollection, this.s.options.readPreference, filter, options);
244
+ };
245
+
246
+ /**
247
+ * Renames the file with the given _id to the given string
248
+ * @method
249
+ * @param {ObjectId} id the id of the file to rename
250
+ * @param {String} filename new name for the file
251
+ * @param {GridFSBucket~errorCallback} [callback]
252
+ */
253
+
254
+ GridFSBucket.prototype.rename = function(id, filename, callback) {
255
+ if (typeof callback === 'function') {
256
+ return _rename(this, id, filename, callback);
257
+ }
258
+
259
+ var _this = this;
260
+ return new this.s.promiseLibrary(function(resolve, reject) {
261
+ _rename(_this, id, filename, function(error, res) {
262
+ if (error) {
263
+ reject(error);
264
+ } else {
265
+ resolve(res);
266
+ }
267
+ });
268
+ });
269
+ };
270
+
271
+ /**
272
+ * @ignore
273
+ */
274
+
275
+ function _rename(_this, id, filename, callback) {
276
+ var filter = { _id: id };
277
+ var update = { $set: { filename: filename } };
278
+ _this.s._filesCollection.updateOne(filter, update, function(error, res) {
279
+ if (error) {
280
+ return callback(error);
281
+ }
282
+ if (!res.result.n) {
283
+ return callback(toError('File with id ' + id + ' not found'));
284
+ }
285
+ callback();
286
+ });
287
+ }
288
+
289
+ /**
290
+ * Removes this bucket's files collection, followed by its chunks collection.
291
+ * @method
292
+ * @param {GridFSBucket~errorCallback} [callback]
293
+ */
294
+
295
+ GridFSBucket.prototype.drop = function(callback) {
296
+ if (typeof callback === 'function') {
297
+ return _drop(this, callback);
298
+ }
299
+
300
+ var _this = this;
301
+ return new this.s.promiseLibrary(function(resolve, reject) {
302
+ _drop(_this, function(error, res) {
303
+ if (error) {
304
+ reject(error);
305
+ } else {
306
+ resolve(res);
307
+ }
308
+ });
309
+ });
310
+ };
311
+
312
+ /**
313
+ * @ignore
314
+ */
315
+
316
+ function _drop(_this, callback) {
317
+ _this.s._filesCollection.drop(function(error) {
318
+ if (error) {
319
+ return callback(error);
320
+ }
321
+ _this.s._chunksCollection.drop(function(error) {
322
+ if (error) {
323
+ return callback(error);
324
+ }
325
+
326
+ return callback();
327
+ });
328
+ });
329
+ }
330
+
331
+ /**
332
+ * Callback format for all GridFSBucket methods that can accept a callback.
333
+ * @callback GridFSBucket~errorCallback
334
+ * @param {MongoError} error An error instance representing any errors that occurred
335
+ */