Skip to content

Commit 1f20d3a

Browse files
committed
add listAll
1 parent b651365 commit 1f20d3a

File tree

3 files changed

+81
-20
lines changed

3 files changed

+81
-20
lines changed

packages/storage/src/implementation/list.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export function listOptionsValidator(p: any) {
105105
throw `Expected maxResults to be less than or equal to ${MAX_MAX_RESULTS}.`;
106106
}
107107
} else if (key === PAGE_TOKEN_KEY) {
108-
if (!type.isString(p[PAGE_TOKEN_KEY])) {
108+
if (p[PAGE_TOKEN_KEY] && !type.isString(p[PAGE_TOKEN_KEY])) {
109109
throw 'Expected pageToken to be string.';
110110
}
111111
} else {

packages/storage/src/reference.ts

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,45 @@ export class Reference {
204204
}
205205

206206
/**
207-
* List items and sub-directories within this directory.
207+
* List all items and prefixes under the current storage reference.
208+
*
209+
* It is a helper method for calling list() recursively until there is no
210+
* more results. The default pagination size is 200.
211+
*
212+
* Note: the results may not be a consistent snapshot if objects are changed
213+
* between paginating requests.
214+
*
215+
* Warning: If there are
216+
*
217+
* @return A promise that resolves with all the items and prefixes under
218+
* the current storage reference. `prefixes` contains references to
219+
* sub-directories and `items` contains references to objects in this
220+
* folder. `nextPageToken` is never returned.
221+
*/
222+
listAll(): Promise<ListResult> {
223+
args.validate('listAll', [], arguments);
224+
const accumulator = {
225+
prefixes: [],
226+
items: [],
227+
};
228+
return this.listAllHelper(accumulator, null).then(() => accumulator);
229+
}
230+
231+
private async listAllHelper(accumulator: ListResult, pageToken?: string): Promise<void> {
232+
let opt: ListOptions = {
233+
maxResults: 1,
234+
pageToken,
235+
};
236+
const nextPage = await this.list(opt);
237+
Array.prototype.push.apply(accumulator.prefixes, nextPage.prefixes);
238+
Array.prototype.push.apply(accumulator.items, nextPage.items);
239+
if (nextPage.nextPageToken) {
240+
await this.listAllHelper(accumulator, nextPage.nextPageToken);
241+
}
242+
}
243+
244+
/**
245+
* List items and prefixes within this directory.
208246
*
209247
* "/" is treated as a path delimiter. Firebase storage does not support
210248
* invalid object path that ends with "/" or contains two consecutive "//".
@@ -214,8 +252,8 @@ export class Reference {
214252
* and `items` to return.
215253
* @param options.pageToken The `nextPageToken` from a previous call to
216254
* list(). If provided, listing is resumed from the previous position.
217-
* @return A promise that resolves with the items and sub-directories.
218-
* `prefixes` contains references to sub-directories and `items`
255+
* @return A promise that resolves with the items and prefixes.
256+
* `prefixes` contains references to prefixes and `items`
219257
* contains references to objects in this folder. `nextPageToken`
220258
* can be passed as `options.pageToken` to get the rest of results.
221259
*/

packages/storage/test/reference.test.ts

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ function makeStorage(url: string) {
3535
function maker(wrapper, loc) {
3636
return ({} as any) as Reference;
3737
}
38+
3839
const authWrapper = new AuthWrapper(
3940
null,
4041
maker,
@@ -56,14 +57,14 @@ describe('Firebase Storage > Reference', () => {
5657
const s = makeStorage('gs://test-bucket/this/ismyobject?hello');
5758
assert.equal(s.toString(), 'gs://test-bucket/this/ismyobject?hello');
5859
});
59-
it("doesn't URL-decode on a gs:// string", () => {
60+
it('doesn\'t URL-decode on a gs:// string', () => {
6061
const s = makeStorage('gs://test-bucket/%3F');
6162
assert.equal(s.toString(), 'gs://test-bucket/%3F');
6263
});
6364
it('ignores URL params and fragments on an http URL', () => {
6465
const s = makeStorage(
6566
`http://${DEFAULT_HOST}/v0/b/test-bucket/o/my/object.txt` +
66-
'?ignoreme#please'
67+
'?ignoreme#please'
6768
);
6869
assert.equal(s.toString(), 'gs://test-bucket/my/object.txt');
6970
});
@@ -77,7 +78,7 @@ describe('Firebase Storage > Reference', () => {
7778
it('ignores URL params and fragments on an https URL', () => {
7879
const s = makeStorage(
7980
`https://${DEFAULT_HOST}/v0/b/test-bucket/o/my/object.txt` +
80-
'?ignoreme#please'
81+
'?ignoreme#please'
8182
);
8283
assert.equal(s.toString(), 'gs://test-bucket/my/object.txt');
8384
});
@@ -91,7 +92,7 @@ describe('Firebase Storage > Reference', () => {
9192
});
9293

9394
describe('toString', () => {
94-
it("Doesn't add trailing slash", () => {
95+
it('Doesn\'t add trailing slash', () => {
9596
const s = makeStorage('gs://test-bucket/foo');
9697
assert.equal(s.toString(), 'gs://test-bucket/foo');
9798
});
@@ -176,7 +177,7 @@ describe('Firebase Storage > Reference', () => {
176177
});
177178
});
178179

179-
it("Doesn't send Authorization on null auth token", done => {
180+
it('Doesn\'t send Authorization on null auth token', done => {
180181
function newSend(
181182
xhrio: TestingXhrIo,
182183
url: string,
@@ -301,7 +302,7 @@ describe('Firebase Storage > Reference', () => {
301302
'storage/invalid-argument'
302303
);
303304
});
304-
it("doesn't throw on good metadata", () => {
305+
it('doesn\'t throw on good metadata', () => {
305306
const goodMetadata = {
306307
md5Hash: 'a',
307308
cacheControl: 'done',
@@ -396,6 +397,15 @@ describe('Firebase Storage > Reference', () => {
396397
});
397398
});
398399

400+
describe('listAll', () => {
401+
it('throws on number arg', () => {
402+
testShared.assertThrows(
403+
testShared.bind(child.listAll, child, 1),
404+
'storage/invalid-argument-count'
405+
);
406+
});
407+
});
408+
399409
describe('list', () => {
400410
it('throws on invalid option', () => {
401411
testShared.assertThrows(
@@ -479,14 +489,14 @@ describe('Firebase Storage > Reference', () => {
479489
});
480490

481491
describe('non-root operations', () => {
482-
it("put doesn't throw", () => {
492+
it('put doesn\'t throw', () => {
483493
assert.doesNotThrow(() => {
484494
child.put(new Blob(['a']));
485495
child.put(new Uint8Array(10));
486496
child.put(new ArrayBuffer(10));
487497
});
488498
});
489-
it("putString doesn't throw", () => {
499+
it('putString doesn\'t throw', () => {
490500
assert.doesNotThrow(() => {
491501
child.putString('raw', StringFormat.RAW);
492502
child.putString('aaaa', StringFormat.BASE64);
@@ -497,17 +507,22 @@ describe('Firebase Storage > Reference', () => {
497507
);
498508
});
499509
});
500-
it("delete doesn't throw", () => {
510+
it('delete doesn\'t throw', () => {
501511
assert.doesNotThrow(() => {
502512
child.delete();
503513
});
504514
});
505-
it("getMetadata doesn't throw", () => {
515+
it('getMetadata doesn\'t throw', () => {
506516
assert.doesNotThrow(() => {
507517
child.getMetadata();
508518
});
509519
});
510-
it("list doesn't throw", () => {
520+
it('listAll doesn\'t throw', () => {
521+
assert.doesNotThrow(() => {
522+
child.listAll();
523+
});
524+
});
525+
it('list doesn\'t throw', () => {
511526
assert.doesNotThrow(() => {
512527
child.list();
513528
});
@@ -520,13 +535,16 @@ describe('Firebase Storage > Reference', () => {
520535
assert.doesNotThrow(() => {
521536
child.list({ maxResults: 4 });
522537
});
538+
assert.doesNotThrow(() => {
539+
child.list({ maxResults: 4, pageToken: null });
540+
});
523541
});
524-
it("updateMetadata doesn't throw", () => {
542+
it('updateMetadata doesn\'t throw', () => {
525543
assert.doesNotThrow(() => {
526544
child.updateMetadata({} as Metadata);
527545
});
528546
});
529-
it("getDownloadURL doesn't throw", () => {
547+
it('getDownloadURL doesn\'t throw', () => {
530548
assert.doesNotThrow(() => {
531549
child.getDownloadURL();
532550
});
@@ -558,12 +576,17 @@ describe('Firebase Storage > Reference', () => {
558576
'storage/invalid-root-operation'
559577
);
560578
});
561-
it("list doesn't throws", () => {
579+
it('listAll doesn\'t throws', () => {
562580
assert.doesNotThrow(() => {
563-
child.list();
581+
root.listAll();
564582
});
583+
});
584+
it('list doesn\'t throws', () => {
565585
assert.doesNotThrow(() => {
566-
child.list({ pageToken: 'xxx', maxResults: 4 });
586+
root.list();
587+
});
588+
assert.doesNotThrow(() => {
589+
root.list({ pageToken: 'xxx', maxResults: 4 });
567590
});
568591
});
569592
it('updateMetadata throws', () => {

0 commit comments

Comments
 (0)