-
Notifications
You must be signed in to change notification settings - Fork 7
/
autoPagination.ts
116 lines (102 loc) · 3.06 KB
/
autoPagination.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Copyright 2019 Cognite AS
import { ListResponse } from './types/types';
// polyfill
if (Symbol.asyncIterator === undefined) {
(Symbol as any).asyncIterator = Symbol.for('asyncIterator');
}
export interface CogniteAsyncIterator<T> extends AsyncIterableIterator<T> {
autoPagingEach: AutoPagingEach<T>;
autoPagingToArray: AutoPagingToArray<T>;
}
/** @hidden */
export function makeAutoPaginationMethods<T>(
firstPagePromise: Promise<ListResponse<T[]>>
) {
let listPromise = firstPagePromise;
let i = 0;
function iterate(
listResult: ListResponse<T[]>
): IteratorResult<T> | Promise<IteratorResult<T>> {
if (i < listResult.items.length) {
return {
value: listResult.items[i++],
done: false,
};
} else if (listResult.next) {
// reset counter, request next page, and recurse.
i = 0;
listPromise = listResult.next();
return listPromise.then(iterate);
}
return { value: undefined!, done: true }; // https://github.com/Microsoft/TypeScript/issues/11375#issuecomment-413037242
}
async function asyncIteratorNext(): Promise<IteratorResult<T>> {
const listResult = await listPromise;
return iterate(listResult);
}
const autoPagingEach = makeAutoPagingEach(asyncIteratorNext);
const autoPagingToArray = makeAutoPagingToArray(autoPagingEach);
const autoPaginationMethods: CogniteAsyncIterator<T> = {
autoPagingEach,
autoPagingToArray,
// Async iterator functions:
next: asyncIteratorNext,
return(): any {
// This is required for `break`.
return {};
},
[Symbol.asyncIterator]: () => autoPaginationMethods,
};
return autoPaginationMethods;
}
export type AutoPagingEachHandler<T> = (
item: T
) => (void | boolean) | Promise<void | boolean>;
export type AutoPagingEach<T> = (
handler: AutoPagingEachHandler<T>
) => Promise<void>;
function makeAutoPagingEach<T>(
asyncIteratorNext: () => Promise<IteratorResult<T>>
): AutoPagingEach<T> {
return async function autoPagingEach(handler: AutoPagingEachHandler<T>) {
async function iterate() {
const iterResult = await asyncIteratorNext();
if (iterResult.done) {
return;
}
const item = iterResult.value;
const shouldContinue = await handler(item);
if (shouldContinue === false) {
return;
}
await iterate();
}
await iterate();
};
}
export interface AutoPagingToArrayOptions {
limit?: number;
}
export type AutoPagingToArray<T> = (
options?: AutoPagingToArrayOptions
) => Promise<T[]>;
function makeAutoPagingToArray<T>(autoPagingEach: AutoPagingEach<T>) {
return async function autoPagingToArray(options?: AutoPagingToArrayOptions) {
let limit = (options && options.limit) || 25;
if (limit === -1) {
limit = Infinity;
}
const items: T[] = [];
await autoPagingEach(async item => {
items.push(item);
if (items.length >= limit) {
return false;
}
});
return items;
};
}
export type CursorAndAsyncIterator<T, Wrapper = T[]> = Promise<
ListResponse<Wrapper>
> &
CogniteAsyncIterator<T>;