Skip to content

Commit 5045792

Browse files
committed
Create a third options argument and allow users to specify a maxPages setting
1 parent 80b4777 commit 5045792

File tree

6 files changed

+82
-1
lines changed

6 files changed

+82
-1
lines changed

README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,35 @@ await octokit.graphql.paginate(
157157
);
158158
```
159159

160+
### Options
161+
162+
You can provide a third argument to `paginate` or `iterator` to modify the behavior of the pagination.
163+
164+
`maxPages` will stop the iteration at the specified number of pages, useful when you don't need all the items in the response but still want to take advantage of the automatic merging.
165+
166+
```
167+
const { repository } = await octokit.graphql.paginate(
168+
`query paginate($cursor: String) {
169+
repository(owner: "octokit", name: "rest.js") {
170+
issues(first: 10, after: $cursor) {
171+
nodes {
172+
title
173+
}
174+
pageInfo {
175+
hasNextPage
176+
endCursor
177+
}
178+
}
179+
}
180+
}`,
181+
{ },
182+
{ maxPages: 10 },
183+
);
184+
```
185+
160186
### Pagination Direction
161187

162-
You can control the pagination direction by the properties deinfed in the `pageInfo` resource.
188+
You can control the pagination direction by the properties defined in the `pageInfo` resource.
163189

164190
For a forward pagination, use:
165191

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Octokit } from "@octokit/core";
22
import { createIterator } from "./iterator";
33
import { createPaginate } from "./paginate";
44
export type { PageInfoForward, PageInfoBackward } from "./page-info";
5+
export type { Options } from "./options";
56

67
export function paginateGraphql(octokit: Octokit) {
78
octokit.graphql;

src/iterator.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,28 @@ import { extractPageInfos } from "./extract-page-info";
22
import { Octokit } from "@octokit/core";
33
import { getCursorFrom, hasAnotherPage } from "./page-info";
44
import { MissingCursorChange } from "./errors";
5+
import type { Options } from "./options";
56

67
const createIterator = (octokit: Octokit) => {
78
return <ResponseType = any>(
89
query: string,
910
initialParameters: Record<string, any> = {},
11+
options: Options = {},
1012
) => {
1113
let nextPageExists = true;
1214
let parameters = { ...initialParameters };
15+
const { maxPages } = options;
16+
let page = 0;
1317

1418
return {
1519
[Symbol.asyncIterator]: () => ({
1620
async next() {
1721
if (!nextPageExists) return { done: true, value: {} as ResponseType };
22+
if (maxPages && page >= maxPages) {
23+
return { done: true, value: {} as ResponseType };
24+
}
25+
26+
page += 1;
1827

1928
const response = await octokit.graphql<ResponseType>(
2029
query,

src/options.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type Options = {
2+
maxPages?: number;
3+
};

src/paginate.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
import { Octokit } from "@octokit/core";
22
import { mergeResponses } from "./merge-responses";
33
import { createIterator } from "./iterator";
4+
import type { Options } from "./options";
45

56
const createPaginate = (octokit: Octokit) => {
67
const iterator = createIterator(octokit);
78
return async <ResponseType extends object = any>(
89
query: string,
910
initialParameters: Record<string, any> = {},
11+
options: Options = {},
1012
): Promise<ResponseType> => {
1113
let mergedResponse: ResponseType = {} as ResponseType;
1214
for await (const response of iterator<ResponseType>(
1315
query,
1416
initialParameters,
17+
options,
1518
)) {
1619
mergedResponse = mergeResponses<ResponseType>(mergedResponse, response);
1720
}

test/paginate.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,45 @@ describe("pagination", () => {
282282
]);
283283
});
284284

285+
it(".paginate.iterator() allows users to pass `maxPages` parameter and stops at the right place.", async (): Promise<void> => {
286+
const responses = createResponsePages({ amount: 3 });
287+
288+
const { octokit, getCallCount, getPassedVariablesForCall } = MockOctokit({
289+
responses,
290+
});
291+
292+
const actualResponse = await octokit.graphql.paginate<TestResponseType>(
293+
`
294+
query paginate ($cursor: String) {
295+
repository(owner: "octokit", name: "rest.js") {
296+
issues(first: 10, after: $cursor) {
297+
nodes {
298+
title
299+
}
300+
pageInfo {
301+
hasNextPage
302+
endCursor
303+
}
304+
}
305+
}
306+
}`,
307+
{},
308+
{ maxPages: 2 },
309+
);
310+
311+
expect(actualResponse).toEqual({
312+
repository: {
313+
issues: {
314+
nodes: [{ title: "Issue 1" }, { title: "Issue 2" }],
315+
pageInfo: { hasNextPage: true, endCursor: "endCursor2" },
316+
},
317+
},
318+
});
319+
expect(getCallCount()).toBe(2);
320+
expect(getPassedVariablesForCall(1)).toBeUndefined();
321+
expect(getPassedVariablesForCall(2)).toEqual({ cursor: "endCursor1" });
322+
});
323+
285324
it("paginate() throws error with path and variable name if cursors do not change between calls.", async (): Promise<void> => {
286325
const [responsePage1, responsePage2] = createResponsePages({ amount: 2 });
287326
responsePage2.repository.issues.pageInfo = {

0 commit comments

Comments
 (0)