Skip to content

Commit a81418a

Browse files
Merge pull request #529 from mziccard/move-file
Storage: add move method to File object
2 parents 81b2c26 + 4a9a1e0 commit a81418a

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed

lib/storage/file.js

+81
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,87 @@ File.prototype.copy = function(destination, callback) {
234234
});
235235
};
236236

237+
/**
238+
* Move this file to another location. By default, this will move
239+
* the file to the same bucket, but you can choose to move it
240+
* to another Bucket by providing either a Bucket or File object.
241+
*
242+
* @throws {Error} If the destination file is not provided.
243+
*
244+
* @param {string|module:storage/bucket|module:storage/file} destination -
245+
* Destination file.
246+
* @param {function=} callback - The callback function.
247+
*
248+
* @example
249+
* //-
250+
* // You can pass in a variety of types for the destination.
251+
* //
252+
* // For all of the below examples, assume we are working with the following
253+
* // Bucket and File objects.
254+
* //-
255+
* var bucket = storage.bucket('my-bucket');
256+
* var file = bucket.file('my-image.png');
257+
*
258+
* //-
259+
* // If you pass in a string for the destination, the file is moved to its
260+
* // current bucket, under the new name provided.
261+
* //-
262+
* file.move('my-image-new.png', function(err, destinationFile, apiResponse) {
263+
* // `my-bucket` no longer contains:
264+
* // - "my-image.png"
265+
* // but contains instead:
266+
* // - "my-image-new.png"
267+
*
268+
* // `destinationFile` is an instance of a File object that refers
269+
* // to your new file.
270+
* });
271+
*
272+
* //-
273+
* // If you pass in a Bucket object, the file will be moved to that bucket
274+
* // using the same name.
275+
* //-
276+
* var anotherBucket = storage.bucket('another-bucket');
277+
* file.move(anotherBucket, function(err, destinationFile, apiResponse) {
278+
* // `my-bucket` no longer contains:
279+
* // - "my-image.png"
280+
* //
281+
* // `another-bucket` now contains:
282+
* // - "my-image.png"
283+
*
284+
* // `destinationFile` is an instance of a File object that refers
285+
* // to your new file.
286+
* });
287+
*
288+
* //-
289+
* // If you pass in a File object, you have complete control over the new
290+
* // bucket and filename.
291+
* //-
292+
* var anotherFile = anotherBucket.file('my-awesome-image.png');
293+
* file.move(anotherFile, function(err, destinationFile, apiResponse) {
294+
* // `my-bucket` no longer contains:
295+
* // - "my-image.png"
296+
* //
297+
* // `another-bucket` now contains:
298+
* // - "my-awesome-image.png"
299+
*
300+
* // Note:
301+
* // The `destinationFile` parameter is equal to `anotherFile`.
302+
* });
303+
*/
304+
File.prototype.move = function(destination, callback) {
305+
callback = callback || util.noop;
306+
var deleteFunction = this.delete.bind(this);
307+
this.copy(destination, function(err, destinationFile, apiResponse) {
308+
if (err) {
309+
callback(err, null, apiResponse);
310+
} else {
311+
deleteFunction(function(err, apiResponse) {
312+
callback(err, destinationFile, apiResponse);
313+
});
314+
}
315+
});
316+
};
317+
237318
/**
238319
* Create a readable stream to read the contents of the remote file. It can be
239320
* piped to a writable stream or listened to for 'data' events to read a file's

test/storage/file.js

+88
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,94 @@ describe('File', function() {
281281
});
282282
});
283283

284+
describe('move', function() {
285+
it('should throw if no destination is provided', function() {
286+
assert.throws(function() {
287+
file.move();
288+
}, /should have a name/);
289+
});
290+
291+
describe('copy to destination', function() {
292+
function assertCopyFile(file, expectedDestination, callback) {
293+
file.copy = function(destination) {
294+
assert.equal(destination, expectedDestination);
295+
callback();
296+
};
297+
}
298+
299+
it('should call copy with string', function(done) {
300+
var newFileName = 'new-file-name.png';
301+
assertCopyFile(file, newFileName, done);
302+
file.move(newFileName);
303+
});
304+
305+
it('should call copy with Bucket', function(done) {
306+
var newBucket = new Bucket({}, 'new-bucket');
307+
assertCopyFile(file, newBucket, done);
308+
file.move(newBucket);
309+
});
310+
311+
it('should call copy with File', function(done) {
312+
var newBucket = new Bucket({}, 'new-bucket');
313+
var newFile = new File(newBucket, 'new-file');
314+
assertCopyFile(file, newFile, done);
315+
file.move(newFile);
316+
});
317+
318+
it('should fail if copy fails', function(done) {
319+
var error = new Error('Error.');
320+
file.copy = function(destination, callback) {
321+
callback(error);
322+
};
323+
file.move('new-filename', function(err) {
324+
assert.equal(err, error);
325+
done();
326+
});
327+
});
328+
});
329+
330+
describe('delete original file', function() {
331+
it('should delete if copy is successful', function(done) {
332+
file.copy = function(destination, callback) {
333+
callback(null);
334+
};
335+
file.delete = function() {
336+
assert.equal(this, file);
337+
done();
338+
};
339+
file.move('new-filename');
340+
});
341+
342+
it('should not delete if copy fails', function(done) {
343+
var deleteCalled = false;
344+
file.copy = function(destination, callback) {
345+
callback(new Error('Error.'));
346+
};
347+
file.delete = function() {
348+
deleteCalled = true;
349+
};
350+
file.move('new-filename', function() {
351+
assert.equal(deleteCalled, false);
352+
done();
353+
});
354+
});
355+
356+
it('should fail if delete fails', function(done) {
357+
var error = new Error('Error.');
358+
file.copy = function(destination, callback) {
359+
callback();
360+
};
361+
file.delete = function(callback) {
362+
callback(error);
363+
};
364+
file.move('new-filename', function(err) {
365+
assert.equal(err, error);
366+
done();
367+
});
368+
});
369+
});
370+
});
371+
284372
describe('createReadStream', function() {
285373
it('should create an authorized request', function(done) {
286374
var expectedPath = util.format('https://{b}.storage.googleapis.com/{o}', {

0 commit comments

Comments
 (0)