Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: pagination parameters as object #1646

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -934,7 +934,7 @@ A function that transform [`Response`](#response) into an array of items. This i
Type: `Function`\
Default: [`Link` header logic](source/index.ts)

The function takes three arguments:
The function takes an object with three properties as single argument:
- `response` - The current response object.
- `allItems` - An array of the emitted items.
- `currentItems` - Items from the current response.
Expand All @@ -955,7 +955,7 @@ const got = require('got');
offset: 0
},
pagination: {
paginate: (response, allItems, currentItems) => {
paginate: ({response, allItems, currentItems}) => {
const previousSearchParams = response.request.options.searchParams;
const previousOffset = previousSearchParams.get('offset');

Expand All @@ -980,14 +980,14 @@ const got = require('got');
###### pagination.filter

Type: `Function`\
Default: `(item, allItems, currentItems) => true`
Default: `({item, allItems, currentItems}) => true`

Checks whether the item should be emitted or not.

###### pagination.shouldContinue

Type: `Function`\
Default: `(item, allItems, currentItems) => true`
Default: `({item, allItems, currentItems}) => true`

Checks whether the pagination should continue.

Expand Down
28 changes: 23 additions & 5 deletions source/as-promise/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,25 @@ All parsing methods supported by Got.
*/
export type ResponseType = 'json' | 'buffer' | 'text';

export interface PaginationOptions<T, R> {
export interface FilterData<ElementType> {
item: ElementType;
allItems: ElementType[];
currentItems: ElementType[];
}

export interface PaginateData<BodyType, ElementType> {
response: Response<BodyType>;
allItems: ElementType[];
currentItems: ElementType[];
}

export interface ShouldContinueData<ElementType> {
item: ElementType;
allItems: ElementType[];
currentItems: ElementType[];
}

export interface PaginationOptions<ElementType, BodyType> {
/**
All options accepted by `got.paginate()`.
*/
Expand All @@ -22,14 +40,14 @@ export interface PaginationOptions<T, R> {

@default response => JSON.parse(response.body)
*/
transform?: (response: Response<R>) => Promise<T[]> | T[];
transform?: (response: Response<BodyType>) => Promise<ElementType[]> | ElementType[];

/**
Checks whether the item should be emitted or not.

@default (item, allItems, currentItems) => true
*/
filter?: (item: T, allItems: T[], currentItems: T[]) => boolean;
filter?: (parameters: FilterData<ElementType>) => boolean;

/**
The function takes three arguments:
Expand Down Expand Up @@ -76,7 +94,7 @@ export interface PaginationOptions<T, R> {
})();
```
*/
paginate?: (response: Response<R>, allItems: T[], currentItems: T[]) => Options | false;
paginate?: (parameters: PaginateData<BodyType, ElementType>) => Options | false;

/**
Checks whether the pagination should continue.
Expand All @@ -86,7 +104,7 @@ export interface PaginationOptions<T, R> {

@default (item, allItems, currentItems) => true
*/
shouldContinue?: (item: T, allItems: T[], currentItems: T[]) => boolean;
shouldContinue?: (parameters: ShouldContinueData<ElementType>) => boolean;

/**
The maximum amount of items that should be emitted.
Expand Down
22 changes: 11 additions & 11 deletions source/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ const create = (defaults: InstanceDefaults): Got => {
throw new TypeError('`options.pagination` must be implemented');
}

const all: T[] = [];
const allItems: T[] = [];
let {countLimit} = pagination;

let numberOfRequests = 0;
Expand All @@ -238,40 +238,40 @@ const create = (defaults: InstanceDefaults): Got => {
// @ts-expect-error FIXME!
// TODO: Throw when result is not an instance of Response
// eslint-disable-next-line no-await-in-loop
const result = (await got(undefined, undefined, normalizedOptions)) as Response;
const response = (await got(undefined, undefined, normalizedOptions)) as Response;

// eslint-disable-next-line no-await-in-loop
const parsed = await pagination.transform(result);
const current: T[] = [];
const parsed = await pagination.transform(response);
const currentItems: T[] = [];

for (const item of parsed) {
if (pagination.filter(item, all, current)) {
if (!pagination.shouldContinue(item, all, current)) {
if (pagination.filter({item, allItems, currentItems})) {
if (!pagination.shouldContinue({item, allItems, currentItems})) {
return;
}

yield item as T;

if (pagination.stackAllItems) {
all.push(item as T);
allItems.push(item as T);
}

current.push(item as T);
currentItems.push(item as T);

if (--countLimit <= 0) {
return;
}
}
}

const optionsToMerge = pagination.paginate(result, all, current);
const optionsToMerge = pagination.paginate({response, allItems, currentItems});

if (optionsToMerge === false) {
return;
}

if (optionsToMerge === result.request.options) {
normalizedOptions = result.request.options;
if (optionsToMerge === response.request.options) {
normalizedOptions = response.request.options;
} else if (optionsToMerge !== undefined) {
normalizedOptions = normalizeArguments(undefined, optionsToMerge, normalizedOptions);
}
Expand Down
2 changes: 1 addition & 1 deletion source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const defaults: InstanceDefaults = {

return JSON.parse(response.body as string);
},
paginate: response => {
paginate: ({response}) => {
if (!Reflect.has(response.headers, 'link')) {
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion test/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1208,7 +1208,7 @@ test('no duplicate hook calls when returning original request options', withServ
};

// Test only two requests, one after another
const paginate = (response: Response) => requestNumber++ === 0 ? response.request.options : false;
const paginate = ({response}: {response: Response}) => requestNumber++ === 0 ? response.request.options : false;

const instance = got.extend({
hooks,
Expand Down
36 changes: 18 additions & 18 deletions test/pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ test('filters elements', withServer, async (t, server, got) => {

const result = await got.paginate.all<number>({
pagination: {
filter: (element: number, allItems: number[], currentItems: number[]) => {
filter: ({item, allItems, currentItems}: {item: number; allItems: number[]; currentItems: number[]}) => {
t.true(Array.isArray(allItems));
t.true(Array.isArray(currentItems));

return element !== 2;
return item !== 2;
}
}
});
Expand Down Expand Up @@ -126,7 +126,7 @@ test('custom paginate function', withServer, async (t, server, got) => {

const result = await got.paginate.all<number>({
pagination: {
paginate: response => {
paginate: ({response}) => {
const url = new URL(response.url);

if (url.search === '?page=3') {
Expand All @@ -148,7 +148,7 @@ test('custom paginate function using allItems', withServer, async (t, server, go

const result = await got.paginate.all<number>({
pagination: {
paginate: (_response, allItems: number[]) => {
paginate: ({allItems}: {allItems: number[]}) => {
if (allItems.length === 2) {
return false;
}
Expand All @@ -166,7 +166,7 @@ test('custom paginate function using currentItems', withServer, async (t, server

const result = await got.paginate.all<number>({
pagination: {
paginate: (_response, _allItems: number[], currentItems: number[]) => {
paginate: ({currentItems}: {currentItems: number[]}) => {
if (currentItems[0] === 3) {
return false;
}
Expand Down Expand Up @@ -208,7 +208,7 @@ test('`shouldContinue` works', withServer, async (t, server, got) => {

const options = {
pagination: {
shouldContinue: (_item: unknown, allItems: unknown[], currentItems: unknown[]) => {
shouldContinue: ({allItems, currentItems}: {item: unknown; allItems: unknown[]; currentItems: unknown[]}) => {
t.true(Array.isArray(allItems));
t.true(Array.isArray(currentItems));

Expand Down Expand Up @@ -357,7 +357,7 @@ test('`hooks` are not duplicated', withServer, async (t, server, got) => {

const result = await got.paginate.all<number>({
pagination: {
paginate: response => {
paginate: ({response}) => {
if ((response.body as string) === '[3]') {
return false; // Stop after page 3
}
Expand Down Expand Up @@ -485,21 +485,21 @@ test('`stackAllItems` set to true', withServer, async (t, server, got) => {
const result = await got.paginate.all<number>({
pagination: {
stackAllItems: true,
filter: (_item, allItems, _currentItems) => {
filter: ({allItems}) => {
t.is(allItems.length, itemCount);

return true;
},
shouldContinue: (_item, allItems, _currentItems) => {
shouldContinue: ({allItems}) => {
t.is(allItems.length, itemCount);

return true;
},
paginate: (response, allItems, currentItems) => {
paginate: ({response, allItems, currentItems}) => {
itemCount += 1;
t.is(allItems.length, itemCount);

return got.defaults.options.pagination!.paginate(response, allItems, currentItems);
return got.defaults.options.pagination!.paginate({response, allItems, currentItems});
}
}
});
Expand All @@ -513,20 +513,20 @@ test('`stackAllItems` set to false', withServer, async (t, server, got) => {
const result = await got.paginate.all<number>({
pagination: {
stackAllItems: false,
filter: (_item, allItems, _currentItems) => {
filter: ({allItems}) => {
t.is(allItems.length, 0);

return true;
},
shouldContinue: (_item, allItems, _currentItems) => {
shouldContinue: ({allItems}) => {
t.is(allItems.length, 0);

return true;
},
paginate: (response, allItems, currentItems) => {
paginate: ({response, allItems, currentItems}) => {
t.is(allItems.length, 0);

return got.defaults.options.pagination!.paginate(response, allItems, currentItems);
return got.defaults.options.pagination!.paginate({response, allItems, currentItems});
}
}
});
Expand Down Expand Up @@ -559,7 +559,7 @@ test('next url in json response', withServer, async (t, server, got) => {
transform: (response: Response<Page>) => {
return [response.body.currentUrl];
},
paginate: (response: Response<Page>) => {
paginate: ({response}: {response: Response<Page>}) => {
const {next} = response.body;

if (!next) {
Expand Down Expand Up @@ -608,7 +608,7 @@ test('pagination using searchParams', withServer, async (t, server, got) => {
transform: (response: Response<Page>) => {
return [response.body.currentUrl];
},
paginate: (response: Response<Page>) => {
paginate: ({response}: {response: Response<Page>}) => {
const {next} = response.body;
const previousPage = Number(response.request.options.searchParams!.get('page'));

Expand Down Expand Up @@ -664,7 +664,7 @@ test('pagination using extended searchParams', withServer, async (t, server, got
transform: (response: Response<Page>) => {
return [response.body.currentUrl];
},
paginate: (response: Response<Page>) => {
paginate: ({response}: {response: Response<Page>}) => {
const {next} = response.body;
const previousPage = Number(response.request.options.searchParams!.get('page'));

Expand Down