Skip to content

Commit

Permalink
Merge pull request googleapis#409 from stephenplusplus/spp--storage-g…
Browse files Browse the repository at this point in the history
…enerations

storage: support specifying a generation
  • Loading branch information
ryanseys committed Apr 17, 2015
2 parents f8a5541 + a450f0c commit 1aff546
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 69 deletions.
45 changes: 41 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 @@ -363,27 +368,50 @@ Bucket.prototype.file = function(name) {
* bucket.getFiles({
* maxResults: 5
* }, function(err, files, nextQuery, apiResponse) {});
*
* //-
* // If your bucket has versioning enabled, you can get all of your files
* // scoped to their generation.
* //-
* bucket.getFiles({
* versions: true
* }, function(err, files, nextQuery, apiResponse) {
* // Each file is scoped to its generation.
* });
*/
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, null, null, resp);
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, resp);
});
};
Expand Down Expand Up @@ -634,6 +662,15 @@ Bucket.prototype.makePublic = function(options, callback) {
* notFoundPage: 'http://example.com/404.html'
* }
* }, function(err, metadata, apiResponse) {});
*
* //-
* // Enable versioning for your bucket.
* //-
* bucket.setMetadata({
* versioning: {
* enabled: true
* }
* }, function(err, metadata, apiResponse) {});
*/
Bucket.prototype.setMetadata = function(metadata, callback) {
var that = this;
Expand Down
94 changes: 73 additions & 21 deletions lib/storage/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,8 @@ var STORAGE_UPLOAD_BASE_URL = 'https://www.googleapis.com/upload/storage/v1/b';
* @param {module:storage/bucket} bucket - The Bucket instance this file is
* attached to.
* @param {string} name - The name of the remote file.
* @param {object=} metadata - Metadata to set on the object. This is useful
* when you are creating a file for the first time, to prevent making an
* extra call to `setMetadata`.
* @param {object=} options - Configuration object.
* @param {number} options.generation - Generation to scope the file to.
*/
/**
* A File object is created from your Bucket object using
Expand All @@ -65,14 +64,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.generation = 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,9 +182,11 @@ 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;
Expand All @@ -209,11 +213,19 @@ File.prototype.copy = function(destination, callback) {
destBucket: destBucket.name,
destName: encodeURIComponent(destName)
});
this.makeReq_('POST', path, null, {}, function(err, resp) {

var query = {};

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

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

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

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

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 @@ -642,13 +660,21 @@ 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, resp) {
var query = {};

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

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

callback(null, resp);
});
};
Expand Down Expand Up @@ -720,13 +746,21 @@ File.prototype.download = function(options, callback) {
File.prototype.getMetadata = function(callback) {
var self = this;
callback = callback || util.noop;

var path = '/o/' + encodeURIComponent(this.name);

this.makeReq_('GET', path, null, true, function(err, resp) {
var query = {};

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

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

self.metadata = resp;
callback(null, self.metadata, resp);
});
Expand Down Expand Up @@ -816,11 +850,17 @@ File.prototype.getSignedUrl = function(options, callback) {
* }, function(err, metadata, apiResponse) {});
*/
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 = {};

this.makeReq_('PATCH', path, null, metadata, function(err, resp) {
if (this.generation) {
query.generation = this.generation;
}

this.makeReq_('PATCH', path, query, metadata, function(err, resp) {
if (err) {
callback(err, null, resp);
return;
Expand Down Expand Up @@ -966,7 +1006,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 @@ -978,7 +1018,13 @@ File.prototype.startResumableUpload_ = function(stream, metadata) {
},
headers: headers,
json: metadata
}, function(err, res, body) {
};

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

makeAuthorizedRequest(reqOpts, function(err, res, body) {
if (err) {
handleError(err);
return;
Expand Down Expand Up @@ -1176,18 +1222,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.generation) {
reqOpts.qs.ifGenerationMatch = this.generation;
}

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
24 changes: 18 additions & 6 deletions lib/storage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,19 +190,31 @@ Storage.prototype.bucket = function(name) {
* @param {function} callback - The callback function.
*
* @example
* storage.createBucket('new-bucket', function(err, bucket, apiResponse) {
* var callback = function(err, bucket, apiResponse) {
* // `bucket` is a Bucket object.
* });
* };
*
* storage.createBucket('new-bucket', callback);
*
* // Specifying metadata.
* //-
* // Specify metadata.
* //-
* var metadata = {
* mainPageSuffix: '/unknown/',
* maxAgeSeconds: 90
* };
*
* var callback = function(err, bucket, apiResponse) {
* // `bucket` is a Bucket object.
* }
* storage.createBucket('new-bucket', metadata, callback);
*
* //-
* // Enable versioning on a new bucket.
* //-
* var metadata = {
* versioning: {
* enabled: true
* }
* };
*
* storage.createBucket('new-bucket', metadata, callback);
*/
Storage.prototype.createBucket = function(name, metadata, callback) {
Expand Down
Loading

0 comments on commit 1aff546

Please sign in to comment.