Skip to content

Commit 7d4ada1

Browse files
storage: support specifying a generation
1 parent 3ce39f6 commit 7d4ada1

File tree

3 files changed

+93
-31
lines changed

3 files changed

+93
-31
lines changed

lib/storage/bucket.js

Lines changed: 5 additions & 2 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
/**

lib/storage/file.js

Lines changed: 83 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,17 @@ var STORAGE_UPLOAD_BASE_URL = 'https://www.googleapis.com/upload/storage/v1/b';
6565
* @alias module:storage/file
6666
* @constructor
6767
*/
68-
function File(bucket, name, metadata) {
68+
function File(bucket, name, options) {
6969
if (!name) {
7070
throw Error('A file name must be specified.');
7171
}
7272

73+
options = options || {};
74+
7375
this.bucket = bucket;
76+
this.explicitGeneration = options.generation;
7477
this.makeReq_ = bucket.makeReq_.bind(bucket);
75-
this.metadata = metadata || {};
78+
this.metadata = {};
7679

7780
Object.defineProperty(this, 'name', {
7881
enumerable: true,
@@ -180,39 +183,55 @@ function File(bucket, name, metadata) {
180183
*/
181184
File.prototype.copy = function(destination, callback) {
182185
var noDestinationError = new Error('Destination file should have a name.');
186+
183187
if (!destination) {
184188
throw noDestinationError;
185189
}
190+
186191
callback = callback || util.noop;
192+
187193
var destBucket;
188194
var destName;
189195
var newFile;
196+
190197
if (util.is(destination, 'string')) {
191198
destBucket = this.bucket;
192199
destName = destination;
193200
}
201+
194202
if (destination.constructor && destination.constructor.name === 'Bucket') {
195203
destBucket = destination;
196204
destName = this.name;
197205
}
206+
198207
if (destination instanceof File) {
199208
destBucket = destination.bucket;
200209
destName = destination.name;
201210
newFile = destination;
202211
}
212+
203213
if (!destName) {
204214
throw noDestinationError;
205215
}
216+
206217
var path = util.format('/o/{srcName}/copyTo/b/{destBucket}/o/{destName}', {
207218
srcName: encodeURIComponent(this.name),
208219
destBucket: destBucket.name,
209220
destName: encodeURIComponent(destName)
210221
});
211-
this.makeReq_('POST', path, null, {}, function(err) {
222+
223+
var query = {};
224+
225+
if (this.explicitGeneration) {
226+
query.sourceGeneration = this.explicitGeneration;
227+
}
228+
229+
this.makeReq_('POST', path, query, {}, function(err) {
212230
if (err) {
213231
callback(err);
214232
return;
215233
}
234+
216235
callback(null, newFile || destBucket.file(destName));
217236
});
218237
};
@@ -330,6 +349,12 @@ File.prototype.createReadStream = function(options) {
330349
uri: uri
331350
};
332351

352+
if (that.explicitGeneration) {
353+
reqOpts.qs = {
354+
generation: that.explicitGeneration
355+
};
356+
}
357+
333358
if (rangeRequest) {
334359
var start = util.is(options.start, 'number') ? options.start : '0';
335360
var end = util.is(options.end, 'number') ? options.end : '';
@@ -641,14 +666,22 @@ File.prototype.createWriteStream = function(options) {
641666
*/
642667
File.prototype.delete = function(callback) {
643668
callback = callback || util.noop;
669+
644670
var path = '/o/' + encodeURIComponent(this.name);
645-
this.makeReq_('DELETE', path, null, true, function(err) {
671+
var query = {};
672+
673+
if (this.explicitGeneration) {
674+
query.generation = this.explicitGeneration;
675+
}
676+
677+
this.makeReq_('DELETE', path, query, true, function(err) {
646678
if (err) {
647679
callback(err);
648680
return;
649681
}
682+
650683
callback();
651-
}.bind(this));
684+
});
652685
};
653686

654687
/**
@@ -717,15 +750,24 @@ File.prototype.download = function(options, callback) {
717750
*/
718751
File.prototype.getMetadata = function(callback) {
719752
callback = callback || util.noop;
753+
754+
var that = this;
720755
var path = '/o/' + encodeURIComponent(this.name);
721-
this.makeReq_('GET', path, null, true, function(err, resp) {
756+
var query = {};
757+
758+
if (this.explicitGeneration) {
759+
query.generation = this.explicitGeneration;
760+
}
761+
762+
this.makeReq_('GET', path, query, true, function(err, resp) {
722763
if (err) {
723764
callback(err);
724765
return;
725766
}
726-
this.metadata = resp;
727-
callback(null, this.metadata);
728-
}.bind(this));
767+
768+
that.metadata = resp;
769+
callback(null, that.metadata);
770+
});
729771
};
730772

731773
/**
@@ -811,11 +853,17 @@ File.prototype.getSignedUrl = function(options, callback) {
811853
* }, function(err, metadata) {});
812854
*/
813855
File.prototype.setMetadata = function(metadata, callback) {
856+
callback = callback || util.noop;
857+
814858
var that = this;
815859
var path = '/o/' + encodeURIComponent(this.name);
816-
callback = callback || util.noop;
860+
var query = {};
861+
862+
if (this.explicitGeneration) {
863+
query.generation = this.explicitGeneration;
864+
}
817865

818-
this.makeReq_('PATCH', path, null, metadata, function(err, resp) {
866+
this.makeReq_('PATCH', path, query, metadata, function(err, resp) {
819867
if (err) {
820868
callback(err);
821869
return;
@@ -961,19 +1009,25 @@ File.prototype.startResumableUpload_ = function(stream, metadata) {
9611009
headers['X-Upload-Content-Type'] = metadata.contentType;
9621010
}
9631011

964-
makeAuthorizedRequest({
1012+
var reqOpts = {
9651013
method: 'POST',
9661014
uri: util.format('{base}/{bucket}/o', {
9671015
base: STORAGE_UPLOAD_BASE_URL,
9681016
bucket: that.bucket.name
9691017
}),
9701018
qs: {
9711019
name: that.name,
972-
uploadType: 'resumable'
1020+
uploadType: 'resumable',
9731021
},
9741022
headers: headers,
9751023
json: metadata
976-
}, function(err, res, body) {
1024+
};
1025+
1026+
if (that.explicitGeneration) {
1027+
reqOpts.qs.ifGenerationMatch = that.explicitGeneration;
1028+
}
1029+
1030+
makeAuthorizedRequest(reqOpts, function(err, res, body) {
9771031
if (err) {
9781032
handleError(err);
9791033
return;
@@ -1171,18 +1225,24 @@ File.prototype.startResumableUpload_ = function(stream, metadata) {
11711225
File.prototype.startSimpleUpload_ = function(stream, metadata) {
11721226
var that = this;
11731227

1228+
var reqOpts = {
1229+
qs: {
1230+
name: that.name
1231+
},
1232+
uri: util.format('{base}/{bucket}/o', {
1233+
base: STORAGE_UPLOAD_BASE_URL,
1234+
bucket: that.bucket.name
1235+
})
1236+
};
1237+
1238+
if (this.explicitGeneration) {
1239+
reqOpts.qs.ifGenerationMatch = this.explicitGeneration;
1240+
}
1241+
11741242
util.makeWritableStream(stream, {
11751243
makeAuthorizedRequest: that.bucket.storage.makeAuthorizedRequest_,
11761244
metadata: metadata,
1177-
request: {
1178-
qs: {
1179-
name: that.name
1180-
},
1181-
uri: util.format('{base}/{bucket}/o', {
1182-
base: STORAGE_UPLOAD_BASE_URL,
1183-
bucket: that.bucket.name
1184-
})
1185-
}
1245+
request: reqOpts
11861246
}, function(data) {
11871247
that.metadata = data;
11881248

test/storage/file.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,9 @@ describe('File', function() {
137137
assert.equal(file.name, FILE_NAME);
138138
});
139139

140-
it('should assign metadata if provided', function() {
141-
var metadata = { a: 'b', c: 'd' };
142-
var newFile = new File(bucket, FILE_NAME, metadata);
143-
assert.deepEqual(newFile.metadata, metadata);
140+
it('should accept specifying a generation', function() {
141+
var file = new File(bucket, 'name', { generation: 2 });
142+
assert.equal(file.explicitGeneration, 2);
144143
});
145144
});
146145

@@ -774,7 +773,7 @@ describe('File', function() {
774773
file.makeReq_ = function(method, path, query, body) {
775774
assert.equal(method, 'DELETE');
776775
assert.equal(path, '/o/' + FILE_NAME);
777-
assert.strictEqual(query, null);
776+
assert.deepEqual(query, {});
778777
assert.strictEqual(body, true);
779778
done();
780779
};
@@ -937,7 +936,7 @@ describe('File', function() {
937936
file.makeReq_ = function(method, path, query, body) {
938937
assert.equal(method, 'GET');
939938
assert.equal(path, '/o/' + FILE_NAME);
940-
assert.strictEqual(query, null);
939+
assert.deepEqual(query, {});
941940
assert.strictEqual(body, true);
942941
done();
943942
};

0 commit comments

Comments
 (0)