Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions lib/storage/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,87 @@ File.prototype.copy = function(destination, callback) {
});
};

/**
* Move this file to another location. By default, this will move
* the file to the same bucket, but you can choose to move it
* to another Bucket by providing either a Bucket or File object.
*
* @throws {Error} If the destination file is not provided.
*
* @param {string|module:storage/bucket|module:storage/file} destination -
* Destination file.
* @param {function=} callback - The callback function.
*
* @example
* //-
* // You can pass in a variety of types for the destination.
* //
* // For all of the below examples, assume we are working with the following
* // Bucket and File objects.
* //-
* var bucket = storage.bucket('my-bucket');
* var file = bucket.file('my-image.png');
*
* //-
* // If you pass in a string for the destination, the file is moved to its
* // current bucket, under the new name provided.
* //-
* file.move('my-image-new.png', function(err, destinationFile, apiResponse) {
* // `my-bucket` no longer contains:
* // - "my-image.png"
* // but contains instead:
* // - "my-image-new.png"
*
* // `destinationFile` is an instance of a File object that refers
* // to your new file.
* });
*
* //-
* // If you pass in a Bucket object, the file will be moved to that bucket
* // using the same name.
* //-
* var anotherBucket = storage.bucket('another-bucket');
* file.move(anotherBucket, function(err, destinationFile, apiResponse) {
* // `my-bucket` no longer contains:
* // - "my-image.png"
* //
* // `another-bucket` now contains:
* // - "my-image.png"
*
* // `destinationFile` is an instance of a File object that refers
* // to your new file.
* });
*
* //-
* // If you pass in a File object, you have complete control over the new
* // bucket and filename.
* //-
* var anotherFile = anotherBucket.file('my-awesome-image.png');
* file.move(anotherFile, function(err, destinationFile, apiResponse) {
* // `my-bucket` no longer contains:
* // - "my-image.png"
* //
* // `another-bucket` now contains:
* // - "my-awesome-image.png"
*
* // Note:
* // The `destinationFile` parameter is equal to `anotherFile`.
* });
*/
File.prototype.move = function(destination, callback) {
callback = callback || util.noop;
var deleteFunction = this.delete.bind(this);
this.copy(destination, function(err, destinationFile, apiResponse) {
if (err) {
callback(err, null, apiResponse);
} else {
deleteFunction(function(err, apiResponse) {
callback(err, destinationFile, apiResponse);
});
}
});
};

/**
* Create a readable stream to read the contents of the remote file. It can be
* piped to a writable stream or listened to for 'data' events to read a file's
Expand Down
88 changes: 88 additions & 0 deletions test/storage/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,94 @@ describe('File', function() {
});
});

describe('move', function() {
it('should throw if no destination is provided', function() {
assert.throws(function() {
file.move();
}, /should have a name/);
});

describe('copy to destination', function() {
function assertCopyFile(file, expectedDestination, callback) {
file.copy = function(destination) {
assert.equal(destination, expectedDestination);
callback();
};
}

it('should call copy with string', function(done) {
var newFileName = 'new-file-name.png';
assertCopyFile(file, newFileName, done);
file.move(newFileName);
});

it('should call copy with Bucket', function(done) {
var newBucket = new Bucket({}, 'new-bucket');
assertCopyFile(file, newBucket, done);
file.move(newBucket);
});

it('should call copy with File', function(done) {
var newBucket = new Bucket({}, 'new-bucket');
var newFile = new File(newBucket, 'new-file');
assertCopyFile(file, newFile, done);
file.move(newFile);
});

it('should fail if copy fails', function(done) {
var error = new Error('Error.');
file.copy = function(destination, callback) {
callback(error);
};
file.move('new-filename', function(err) {
assert.equal(err, error);
done();
});
});
});

describe('delete original file', function() {
it('should delete if copy is successful', function(done) {
file.copy = function(destination, callback) {
callback(null);
};
file.delete = function() {
assert.equal(this, file);
done();
};
file.move('new-filename');
});

it('should not delete if copy fails', function(done) {
var deleteCalled = false;
file.copy = function(destination, callback) {
callback(new Error('Error.'));
};
file.delete = function() {
deleteCalled = true;
};
file.move('new-filename', function() {
assert.equal(deleteCalled, false);
done();
});
});

it('should fail if delete fails', function(done) {
var error = new Error('Error.');
file.copy = function(destination, callback) {
callback();
};
file.delete = function(callback) {
callback(error);
};
file.move('new-filename', function(err) {
assert.equal(err, error);
done();
});
});
});
});

describe('createReadStream', function() {
it('should create an authorized request', function(done) {
var expectedPath = util.format('https://{b}.storage.googleapis.com/{o}', {
Expand Down