Skip to content

Commit 3aa2fae

Browse files
storage: support specifying a generation
1 parent f8a5541 commit 3aa2fae

6 files changed

Lines changed: 359 additions & 68 deletions

File tree

lib/storage/bucket.js

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,13 +315,16 @@ Bucket.prototype.delete = function(callback) {
315315
* the different use cases you may have.
316316
*
317317
* @param {string} name - The name of the file in this bucket.
318+
* @param {object=} options - Configuration options.
319+
* @param {string|number} options.generation - Only use a specific revision of
320+
* this file.
318321
* @return {module:storage/file}
319322
*
320323
* @example
321324
* var file = bucket.file('my-existing-file.png');
322325
*/
323-
Bucket.prototype.file = function(name) {
324-
return new File(this, name);
326+
Bucket.prototype.file = function(name, options) {
327+
return new File(this, name, options);
325328
};
326329

327330
/**
@@ -339,6 +342,8 @@ Bucket.prototype.file = function(name) {
339342
* return.
340343
* @param {string} query.pageToken - A previously-returned page token
341344
* representing part of the larger set of results to view.
345+
* @param {bool} query.versions - If true, returns File objects scoped to their
346+
* versions.
342347
* @param {function} callback - The callback function.
343348
*
344349
* @example
@@ -363,27 +368,50 @@ Bucket.prototype.file = function(name) {
363368
* bucket.getFiles({
364369
* maxResults: 5
365370
* }, function(err, files, nextQuery, apiResponse) {});
371+
*
372+
* //-
373+
* // If your bucket has versioning enabled, you can get all of your files
374+
* // scoped to their generation.
375+
* //-
376+
* bucket.getFiles({
377+
* versions: true
378+
* }, function(err, files, nextQuery, apiResponse) {
379+
* // Each file is scoped to its generation.
380+
* });
366381
*/
367382
Bucket.prototype.getFiles = function(query, callback) {
368-
var that = this;
383+
var self = this;
384+
369385
if (!callback) {
370386
callback = query;
371387
query = {};
372388
}
389+
373390
this.makeReq_('GET', '/o', query, true, function(err, resp) {
374391
if (err) {
375392
callback(err, null, null, resp);
376393
return;
377394
}
395+
378396
var files = (resp.items || []).map(function(item) {
379-
var file = that.file(item.name);
397+
var options = {};
398+
399+
if (query.versions) {
400+
options.generation = item.generation;
401+
}
402+
403+
var file = self.file(item.name, options);
380404
file.metadata = item;
405+
381406
return file;
382407
});
408+
383409
var nextQuery = null;
410+
384411
if (resp.nextPageToken) {
385412
nextQuery = extend({}, query, { pageToken: resp.nextPageToken });
386413
}
414+
387415
callback(null, files, nextQuery, resp);
388416
});
389417
};
@@ -634,6 +662,15 @@ Bucket.prototype.makePublic = function(options, callback) {
634662
* notFoundPage: 'http://example.com/404.html'
635663
* }
636664
* }, function(err, metadata, apiResponse) {});
665+
*
666+
* //-
667+
* // Enable versioning for your bucket.
668+
* //-
669+
* bucket.setMetadata({
670+
* versioning: {
671+
* enabled: true
672+
* }
673+
* }, function(err, metadata, apiResponse) {});
637674
*/
638675
Bucket.prototype.setMetadata = function(metadata, callback) {
639676
var that = this;

lib/storage/file.js

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,8 @@ var STORAGE_UPLOAD_BASE_URL = 'https://www.googleapis.com/upload/storage/v1/b';
5454
* @param {module:storage/bucket} bucket - The Bucket instance this file is
5555
* attached to.
5656
* @param {string} name - The name of the remote file.
57-
* @param {object=} metadata - Metadata to set on the object. This is useful
58-
* when you are creating a file for the first time, to prevent making an
59-
* extra call to `setMetadata`.
57+
* @param {object=} options - Configuration object.
58+
* @param {number} options.generation - Generation to scope the file to.
6059
*/
6160
/**
6261
* A File object is created from your Bucket object using
@@ -65,14 +64,17 @@ var STORAGE_UPLOAD_BASE_URL = 'https://www.googleapis.com/upload/storage/v1/b';
6564
* @alias module:storage/file
6665
* @constructor
6766
*/
68-
function File(bucket, name, metadata) {
67+
function File(bucket, name, options) {
6968
if (!name) {
7069
throw Error('A file name must be specified.');
7170
}
7271

72+
options = options || {};
73+
7374
this.bucket = bucket;
75+
this.explicitGeneration = parseInt(options.generation, 10);
7476
this.makeReq_ = bucket.makeReq_.bind(bucket);
75-
this.metadata = metadata || {};
77+
this.metadata = {};
7678

7779
Object.defineProperty(this, 'name', {
7880
enumerable: true,
@@ -180,9 +182,11 @@ function File(bucket, name, metadata) {
180182
*/
181183
File.prototype.copy = function(destination, callback) {
182184
var noDestinationError = new Error('Destination file should have a name.');
185+
183186
if (!destination) {
184187
throw noDestinationError;
185188
}
189+
186190
callback = callback || util.noop;
187191

188192
var destBucket;
@@ -209,11 +213,19 @@ File.prototype.copy = function(destination, callback) {
209213
destBucket: destBucket.name,
210214
destName: encodeURIComponent(destName)
211215
});
212-
this.makeReq_('POST', path, null, {}, function(err, resp) {
216+
217+
var query = {};
218+
219+
if (this.explicitGeneration) {
220+
query.sourceGeneration = this.explicitGeneration;
221+
}
222+
223+
this.makeReq_('POST', path, query, null, function(err, resp) {
213224
if (err) {
214225
callback(err, null, resp);
215226
return;
216227
}
228+
217229
callback(null, newFile || destBucket.file(destName), resp);
218230
});
219231
};
@@ -331,6 +343,12 @@ File.prototype.createReadStream = function(options) {
331343
uri: uri
332344
};
333345

346+
if (that.explicitGeneration) {
347+
reqOpts.qs = {
348+
generation: that.explicitGeneration
349+
};
350+
}
351+
334352
if (rangeRequest) {
335353
var start = util.is(options.start, 'number') ? options.start : '0';
336354
var end = util.is(options.end, 'number') ? options.end : '';
@@ -642,13 +660,21 @@ File.prototype.createWriteStream = function(options) {
642660
*/
643661
File.prototype.delete = function(callback) {
644662
callback = callback || util.noop;
663+
645664
var path = '/o/' + encodeURIComponent(this.name);
646665

647-
this.makeReq_('DELETE', path, null, true, function(err, resp) {
666+
var query = {};
667+
668+
if (this.explicitGeneration) {
669+
query.generation = this.explicitGeneration;
670+
}
671+
672+
this.makeReq_('DELETE', path, query, null, function(err, resp) {
648673
if (err) {
649674
callback(err, resp);
650675
return;
651676
}
677+
652678
callback(null, resp);
653679
});
654680
};
@@ -720,13 +746,21 @@ File.prototype.download = function(options, callback) {
720746
File.prototype.getMetadata = function(callback) {
721747
var self = this;
722748
callback = callback || util.noop;
749+
723750
var path = '/o/' + encodeURIComponent(this.name);
724751

725-
this.makeReq_('GET', path, null, true, function(err, resp) {
752+
var query = {};
753+
754+
if (this.explicitGeneration) {
755+
query.generation = this.explicitGeneration;
756+
}
757+
758+
this.makeReq_('GET', path, query, null, function(err, resp) {
726759
if (err) {
727760
callback(err, null, resp);
728761
return;
729762
}
763+
730764
self.metadata = resp;
731765
callback(null, self.metadata, resp);
732766
});
@@ -816,11 +850,17 @@ File.prototype.getSignedUrl = function(options, callback) {
816850
* }, function(err, metadata, apiResponse) {});
817851
*/
818852
File.prototype.setMetadata = function(metadata, callback) {
853+
callback = callback || util.noop;
854+
819855
var that = this;
820856
var path = '/o/' + encodeURIComponent(this.name);
821-
callback = callback || util.noop;
857+
var query = {};
822858

823-
this.makeReq_('PATCH', path, null, metadata, function(err, resp) {
859+
if (this.explicitGeneration) {
860+
query.generation = this.explicitGeneration;
861+
}
862+
863+
this.makeReq_('PATCH', path, query, metadata, function(err, resp) {
824864
if (err) {
825865
callback(err, null, resp);
826866
return;
@@ -966,7 +1006,7 @@ File.prototype.startResumableUpload_ = function(stream, metadata) {
9661006
headers['X-Upload-Content-Type'] = metadata.contentType;
9671007
}
9681008

969-
makeAuthorizedRequest({
1009+
var reqOpts = {
9701010
method: 'POST',
9711011
uri: util.format('{base}/{bucket}/o', {
9721012
base: STORAGE_UPLOAD_BASE_URL,
@@ -978,7 +1018,13 @@ File.prototype.startResumableUpload_ = function(stream, metadata) {
9781018
},
9791019
headers: headers,
9801020
json: metadata
981-
}, function(err, res, body) {
1021+
};
1022+
1023+
if (that.explicitGeneration) {
1024+
reqOpts.qs.ifGenerationMatch = that.explicitGeneration;
1025+
}
1026+
1027+
makeAuthorizedRequest(reqOpts, function(err, res, body) {
9821028
if (err) {
9831029
handleError(err);
9841030
return;
@@ -1176,18 +1222,24 @@ File.prototype.startResumableUpload_ = function(stream, metadata) {
11761222
File.prototype.startSimpleUpload_ = function(stream, metadata) {
11771223
var that = this;
11781224

1225+
var reqOpts = {
1226+
qs: {
1227+
name: that.name
1228+
},
1229+
uri: util.format('{base}/{bucket}/o', {
1230+
base: STORAGE_UPLOAD_BASE_URL,
1231+
bucket: that.bucket.name
1232+
})
1233+
};
1234+
1235+
if (this.explicitGeneration) {
1236+
reqOpts.qs.ifGenerationMatch = this.explicitGeneration;
1237+
}
1238+
11791239
util.makeWritableStream(stream, {
11801240
makeAuthorizedRequest: that.bucket.storage.makeAuthorizedRequest_,
11811241
metadata: metadata,
1182-
request: {
1183-
qs: {
1184-
name: that.name
1185-
},
1186-
uri: util.format('{base}/{bucket}/o', {
1187-
base: STORAGE_UPLOAD_BASE_URL,
1188-
bucket: that.bucket.name
1189-
})
1190-
}
1242+
request: reqOpts
11911243
}, function(data) {
11921244
that.metadata = data;
11931245

lib/storage/index.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,19 +190,31 @@ Storage.prototype.bucket = function(name) {
190190
* @param {function} callback - The callback function.
191191
*
192192
* @example
193-
* storage.createBucket('new-bucket', function(err, bucket, apiResponse) {
193+
* var callback = function(err, bucket, apiResponse) {
194194
* // `bucket` is a Bucket object.
195-
* });
195+
* };
196+
*
197+
* storage.createBucket('new-bucket', callback);
196198
*
197-
* // Specifying metadata.
199+
* //-
200+
* // Specify metadata.
201+
* //-
198202
* var metadata = {
199203
* mainPageSuffix: '/unknown/',
200204
* maxAgeSeconds: 90
201205
* };
202206
*
203-
* var callback = function(err, bucket, apiResponse) {
204-
* // `bucket` is a Bucket object.
205-
* }
207+
* storage.createBucket('new-bucket', metadata, callback);
208+
*
209+
* //-
210+
* // Enable versioning on a new bucket.
211+
* //-
212+
* var metadata = {
213+
* versioning: {
214+
* enabled: true
215+
* }
216+
* };
217+
*
206218
* storage.createBucket('new-bucket', metadata, callback);
207219
*/
208220
Storage.prototype.createBucket = function(name, metadata, callback) {

0 commit comments

Comments
 (0)