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

[@azure-rest/core-paging] Use @azure/core-paging's getPagedAsyncIterator #16891

Merged
merged 7 commits into from
Aug 14, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 2 additions & 2 deletions sdk/core/core-client-paging-rest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"docs": "typedoc --excludePrivate --excludeNotExported --excludeExternals --stripInternal --mode file --out ./dist/docs ./src",
"execute:samples": "echo skipped",
"extract-api": "tsc -p . && api-extractor run --local",
"format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
"format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\"",
"integration-test:browser": "echo skipped",
"integration-test:node": "echo skipped",
"integration-test": "npm run integration-test:node && npm run integration-test:browser",
Expand Down Expand Up @@ -58,7 +58,7 @@
"sideEffects": false,
"prettier": "@azure/eslint-plugin-azure-sdk/prettier.json",
"dependencies": {
"@azure/core-paging": "^1.1.1",
"@azure/core-paging": "^1.2.0",
"@azure/core-rest-pipeline": "^1.1.0",
"@azure-rest/core-client": "1.0.0-beta.6",
"tslib": "^2.2.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface PaginateOptions {
}

// @public
export function paginateResponse<TReturn>(client: Client, initialResponse: HttpResponse, options?: PaginateOptions): PagedAsyncIterableIterator<TReturn, TReturn[]>;
export function paginateResponse<TReturn>(client: Client, initialResponse: HttpResponse, options?: PaginateOptions): PagedAsyncIterableIterator<TReturn>;


```
83 changes: 30 additions & 53 deletions sdk/core/core-client-paging-rest/src/paginate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
HttpResponse,
PathUncheckedResponse,
} from "@azure-rest/core-client";
import { PagedAsyncIterableIterator } from "@azure/core-paging";
import { getPagedAsyncIterator, PagedAsyncIterableIterator, PagedResult } from "@azure/core-paging";

const Http2xxStatusCodes = ["200", "201", "202", "203", "204", "205", "206", "207", "208", "226"];

Expand Down Expand Up @@ -42,67 +42,41 @@ export interface PaginateOptions {
* @param options - Options to use custom property names for pagination
* @returns - return a PagedAsyncIterableIterator that can be used to iterate the elements
*/
export function paginateResponse<TReturn>(
export function paginateResponse<TElement>(
client: Client,
initialResponse: HttpResponse,
options: PaginateOptions = {}
): PagedAsyncIterableIterator<TReturn, TReturn[]> {
const iter = listAll<TReturn>(client, initialResponse, options);
return {
next() {
return iter.next();
},
[Symbol.asyncIterator]() {
return this;
},
byPage: () => {
return listPage<TReturn>(client, initialResponse, options);
): PagedAsyncIterableIterator<TElement> {
let firstRun = true;
const pagedResult: PagedResult<TElement[]> = {
firstPageLink: "",
async getPage(pageLink: string) {
let result: HttpResponse | undefined = undefined;
if (firstRun) {
result = initialResponse;
firstRun = false;
} else {
result = await client.pathUnchecked(pageLink).get();
}
deyaaeldeen marked this conversation as resolved.
Show resolved Hide resolved
checkPagingRequest(result);
const nextLink = getNextLink(result.body as Record<string, unknown>, options);
const values = getElements<TElement>(result.body as Record<string, unknown>, options);
return {
page: values,
// According to x-ms-pageable is the nextLinkName is set to null we should only
// return the first page and skip any additional queries even if the initial response
// contains a nextLink.
nextPageLink: options.nextLinkName === null ? undefined : nextLink,
};
},
};
}

async function* listAll<T>(
client: Client,
initialResponse: PathUncheckedResponse,
paginateOptions: PaginateOptions
): AsyncIterableIterator<T> {
for await (const page of listPage<T>(client, initialResponse, paginateOptions)) {
yield* page;
}
}

async function* listPage<T = Record<string, unknown>[]>(
client: Client,
initialResponse: PathUncheckedResponse,
options: PaginateOptions
): AsyncIterableIterator<T[]> {
let result = initialResponse;
checkPagingRequest(result);
let nextLink = getNextLink(result.body, options);
let values = getElements<T>(result.body, options);

yield values;

// According to x-ms-pageable is the nextLinkName is set to null we should only
// return the first page and skip any additional queries even if the initial response
// contains a nextLink.
if (options.nextLinkName === null) {
return;
}

while (nextLink) {
result = await client.pathUnchecked(nextLink).get();
checkPagingRequest(result);
nextLink = getNextLink(result.body, options);
values = getElements<T>(result.body, options);
yield values;
}
return getPagedAsyncIterator(pagedResult);
}

/**
* Checks if a request failed
*/
function checkPagingRequest(response: PathUncheckedResponse) {
function checkPagingRequest(response: PathUncheckedResponse): void {
if (!Http2xxStatusCodes.includes(response.status)) {
throw createRestError(
`Pagination failed with unexpected statusCode ${response.status}`,
Expand All @@ -114,7 +88,10 @@ function checkPagingRequest(response: PathUncheckedResponse) {
/**
* Gets for the value of nextLink in the body. If a custom nextLinkName was provided, it will be used instead of default
*/
function getNextLink(body: Record<string, unknown>, paginateOptions: PaginateOptions = {}) {
function getNextLink(
body: Record<string, unknown>,
deyaaeldeen marked this conversation as resolved.
Show resolved Hide resolved
paginateOptions: PaginateOptions = {}
): string | undefined {
const nextLinkName = paginateOptions.nextLinkName ?? DEFAULT_NEXTLINK;
const nextLink = body[nextLinkName];

Expand Down
2 changes: 1 addition & 1 deletion sdk/core/core-client-paging-rest/test/paginate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ interface MockResponse {
* @param response - Responses to return, the actual request url is matched to one of the paths in the responses and the defined object is returned.
* if no path matches a 404 error is returned
*/
function mockResponse(client: Client, responses: MockResponse[]) {
function mockResponse(client: Client, responses: MockResponse[]): void {
let count = 0;

client.pipeline.addPolicy({
Expand Down