Skip to content

Commit

Permalink
storage: support specifying a generation
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenplusplus committed Apr 16, 2015
1 parent 845416d commit 7d6161b
Show file tree
Hide file tree
Showing 5 changed files with 331 additions and 63 deletions.
26 changes: 22 additions & 4 deletions lib/storage/bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,13 +315,16 @@ Bucket.prototype.delete = function(callback) {
* the different use cases you may have.
*
* @param {string} name - The name of the file in this bucket.
* @param {object=} options - Configuration options.
* @param {string|number} options.generation - Only use a specific revision of
* this file.
* @return {module:storage/file}
*
* @example
* var file = bucket.file('my-existing-file.png');
*/
Bucket.prototype.file = function(name) {
return new File(this, name);
Bucket.prototype.file = function(name, options) {
return new File(this, name, options);
};

/**
Expand All @@ -339,6 +342,8 @@ Bucket.prototype.file = function(name) {
* return.
* @param {string} query.pageToken - A previously-returned page token
* representing part of the larger set of results to view.
* @param {bool} query.versions - If true, returns File objects scoped to their
* versions.
* @param {function} callback - The callback function.
*
* @example
Expand All @@ -365,25 +370,38 @@ Bucket.prototype.file = function(name) {
* }, function(err, files, nextQuery) {});
*/
Bucket.prototype.getFiles = function(query, callback) {
var that = this;
var self = this;

if (!callback) {
callback = query;
query = {};
}

this.makeReq_('GET', '/o', query, true, function(err, resp) {
if (err) {
callback(err);
return;
}

var files = (resp.items || []).map(function(item) {
var file = that.file(item.name);
var options = {};

if (query.versions) {
options.generation = item.generation;
}

var file = self.file(item.name, options);
file.metadata = item;

return file;
});

var nextQuery = null;

if (resp.nextPageToken) {
nextQuery = extend({}, query, { pageToken: resp.nextPageToken });
}

callback(null, files, nextQuery);
});
};
Expand Down
104 changes: 82 additions & 22 deletions lib/storage/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,17 @@ var STORAGE_UPLOAD_BASE_URL = 'https://www.googleapis.com/upload/storage/v1/b';
* @alias module:storage/file
* @constructor
*/
function File(bucket, name, metadata) {
function File(bucket, name, options) {
if (!name) {
throw Error('A file name must be specified.');
}

options = options || {};

this.bucket = bucket;
this.explicitGeneration = parseInt(options.generation, 10);
this.makeReq_ = bucket.makeReq_.bind(bucket);
this.metadata = metadata || {};
this.metadata = {};

Object.defineProperty(this, 'name', {
enumerable: true,
Expand Down Expand Up @@ -180,39 +183,55 @@ function File(bucket, name, metadata) {
*/
File.prototype.copy = function(destination, callback) {
var noDestinationError = new Error('Destination file should have a name.');

if (!destination) {
throw noDestinationError;
}

callback = callback || util.noop;

var destBucket;
var destName;
var newFile;

if (util.is(destination, 'string')) {
destBucket = this.bucket;
destName = destination;
}

if (destination.constructor && destination.constructor.name === 'Bucket') {
destBucket = destination;
destName = this.name;
}

if (destination instanceof File) {
destBucket = destination.bucket;
destName = destination.name;
newFile = destination;
}

if (!destName) {
throw noDestinationError;
}

var path = util.format('/o/{srcName}/copyTo/b/{destBucket}/o/{destName}', {
srcName: encodeURIComponent(this.name),
destBucket: destBucket.name,
destName: encodeURIComponent(destName)
});
this.makeReq_('POST', path, null, {}, function(err) {

var query = {};

if (this.explicitGeneration) {
query.sourceGeneration = this.explicitGeneration;
}

this.makeReq_('POST', path, query, null, function(err) {
if (err) {
callback(err);
return;
}

callback(null, newFile || destBucket.file(destName));
});
};
Expand Down Expand Up @@ -330,6 +349,12 @@ File.prototype.createReadStream = function(options) {
uri: uri
};

if (that.explicitGeneration) {
reqOpts.qs = {
generation: that.explicitGeneration
};
}

if (rangeRequest) {
var start = util.is(options.start, 'number') ? options.start : '0';
var end = util.is(options.end, 'number') ? options.end : '';
Expand Down Expand Up @@ -641,14 +666,22 @@ File.prototype.createWriteStream = function(options) {
*/
File.prototype.delete = function(callback) {
callback = callback || util.noop;

var path = '/o/' + encodeURIComponent(this.name);
this.makeReq_('DELETE', path, null, true, function(err) {
var query = {};

if (this.explicitGeneration) {
query.generation = this.explicitGeneration;
}

this.makeReq_('DELETE', path, query, true, function(err) {
if (err) {
callback(err);
return;
}

callback();
}.bind(this));
});
};

/**
Expand Down Expand Up @@ -717,15 +750,24 @@ File.prototype.download = function(options, callback) {
*/
File.prototype.getMetadata = function(callback) {
callback = callback || util.noop;

var that = this;
var path = '/o/' + encodeURIComponent(this.name);
this.makeReq_('GET', path, null, true, function(err, resp) {
var query = {};

if (this.explicitGeneration) {
query.generation = this.explicitGeneration;
}

this.makeReq_('GET', path, query, null, function(err, resp) {
if (err) {
callback(err);
return;
}
this.metadata = resp;
callback(null, this.metadata);
}.bind(this));

that.metadata = resp;
callback(null, that.metadata);
});
};

/**
Expand Down Expand Up @@ -811,11 +853,17 @@ File.prototype.getSignedUrl = function(options, callback) {
* }, function(err, metadata) {});
*/
File.prototype.setMetadata = function(metadata, callback) {
callback = callback || util.noop;

var that = this;
var path = '/o/' + encodeURIComponent(this.name);
callback = callback || util.noop;
var query = {};

if (this.explicitGeneration) {
query.generation = this.explicitGeneration;
}

this.makeReq_('PATCH', path, null, metadata, function(err, resp) {
this.makeReq_('PATCH', path, query, metadata, function(err, resp) {
if (err) {
callback(err);
return;
Expand Down Expand Up @@ -961,7 +1009,7 @@ File.prototype.startResumableUpload_ = function(stream, metadata) {
headers['X-Upload-Content-Type'] = metadata.contentType;
}

makeAuthorizedRequest({
var reqOpts = {
method: 'POST',
uri: util.format('{base}/{bucket}/o', {
base: STORAGE_UPLOAD_BASE_URL,
Expand All @@ -973,7 +1021,13 @@ File.prototype.startResumableUpload_ = function(stream, metadata) {
},
headers: headers,
json: metadata
}, function(err, res, body) {
};

if (that.explicitGeneration) {
reqOpts.qs.ifGenerationMatch = that.explicitGeneration;
}

makeAuthorizedRequest(reqOpts, function(err, res, body) {
if (err) {
handleError(err);
return;
Expand Down Expand Up @@ -1171,18 +1225,24 @@ File.prototype.startResumableUpload_ = function(stream, metadata) {
File.prototype.startSimpleUpload_ = function(stream, metadata) {
var that = this;

var reqOpts = {
qs: {
name: that.name
},
uri: util.format('{base}/{bucket}/o', {
base: STORAGE_UPLOAD_BASE_URL,
bucket: that.bucket.name
})
};

if (this.explicitGeneration) {
reqOpts.qs.ifGenerationMatch = this.explicitGeneration;
}

util.makeWritableStream(stream, {
makeAuthorizedRequest: that.bucket.storage.makeAuthorizedRequest_,
metadata: metadata,
request: {
qs: {
name: that.name
},
uri: util.format('{base}/{bucket}/o', {
base: STORAGE_UPLOAD_BASE_URL,
bucket: that.bucket.name
})
}
request: reqOpts
}, function(data) {
that.metadata = data;

Expand Down
Loading

0 comments on commit 7d6161b

Please sign in to comment.