UNPKG

@microsoft/msgraph-sdk-core

Version:
215 lines 8.88 kB
/** * ------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. * See License in the project root for license information. * ------------------------------------------------------------------------------------------- */ /** * @module PageIterator */ import { RequestInformation, HttpMethod, } from "@microsoft/kiota-abstractions"; /** * Class representing a PageIterator to iterate over paginated collections. * @template T - The type of the items in the collection. * * This class provides methods to iterate over a collection of items that are paginated. * It handles fetching the next set of items when the current page is exhausted. * The iteration can be paused and resumed, and the state of the iterator can be queried. * * The PageIterator uses a callback function to process each item in the collection. * The callback function should return a boolean indicating whether to continue the iteration. * * The PageIterator also supports error handling through error mappings and can be configured * with custom request options. */ export class PageIterator { /** * @public * @constructor * Creates new instance for PageIterator * @returns An instance of a PageIterator * @param requestAdapter - The request adapter * @param pageResult - The page collection result of T * @param callback - The callback function to be called on each item * @param errorMappings - The error mappings * @param parsableFactory - The factory to create the parsable object collection * @param options - The request options to configure the request */ constructor(requestAdapter, pageResult, callback, parsableFactory, errorMappings, options) { if (!requestAdapter) { const error = new Error("Request adapter is undefined, Please provide a valid request adapter"); error.name = "Invalid Request Adapter Error"; throw error; } if (!pageResult) { const error = new Error("Page result is undefined, Please provide a valid page result"); error.name = "Invalid Page Result Error"; throw error; } if (!callback) { const error = new Error("Callback is undefined, Please provide a valid callback"); error.name = "Invalid Callback Error"; throw error; } if (!parsableFactory) { const error = new Error("Parsable factory is undefined, Please provide a valid parsable factory"); error.name = "Invalid Parsable Factory Error"; throw error; } if (!errorMappings) { const error = new Error("Error mappings is undefined, Please provide a valid error mappings"); error.name = "Invalid Error Mappings Error"; throw error; } this.requestAdapter = requestAdapter; this.currentPage = pageResult; this.cursor = 0; this.errorMappings = errorMappings; this.parsableFactory = parsableFactory; this.callback = callback; if (!options) { options = {}; } this.options = options; this.pagingState = "NotStarted"; } /** * @public * Getter to get the deltaLink in the current response * @returns A deltaLink which is being used to make delta requests in future */ getOdataDeltaLink() { var _a, _b, _c; const deltaLink = (_a = this.currentPage) === null || _a === void 0 ? void 0 : _a["@odata.deltaLink"]; return (_c = (_b = this.currentPage) === null || _b === void 0 ? void 0 : _b.odataDeltaLink) !== null && _c !== void 0 ? _c : deltaLink; } /** * @public * Getter to get the nextLink in the current response * @returns A nextLink which is being used to make requests in future */ getOdataNextLink() { var _a, _b, _c; const nextLink = (_a = this.currentPage) === null || _a === void 0 ? void 0 : _a["@odata.nextLink"]; return (_c = (_b = this.currentPage) === null || _b === void 0 ? void 0 : _b.odataNextLink) !== null && _c !== void 0 ? _c : nextLink; } /** * @public * @async * Iterates over the collection and kicks callback for each item on iteration. Fetches next set of data through nextLink and iterates over again * This happens until the nextLink is drained out or the user responds with a red flag to continue from callback */ async iterate() { var _a, _b; while (true) { if (this.pagingState === "Complete") { return; } if (this.pagingState === "Delta") { const nextPage = await this.fetchNextPage(); if (!nextPage) { this.pagingState = "Complete"; return; } this.currentPage = nextPage; } const advance = this.enumeratePage(); if (!advance) { return; } const nextLink = this.getOdataNextLink(); const deltaLink = this.getOdataDeltaLink(); const hasNextPageLink = nextLink || deltaLink; const pageSize = (_b = (_a = this.currentPage) === null || _a === void 0 ? void 0 : _a.value.length) !== null && _b !== void 0 ? _b : 0; const isEndOfPage = !hasNextPageLink && this.cursor >= pageSize; if (isEndOfPage) { this.pagingState = "Complete"; return; } if (hasNextPageLink && this.cursor >= pageSize) { this.cursor = 0; if (deltaLink) { this.pagingState = "Delta"; return; } const nextPage = await this.fetchNextPage(); if (!nextPage) { this.pagingState = "Complete"; return; } this.currentPage = nextPage; } } } /** * @public * Getter to get the state of the iterator */ getPagingState() { return this.pagingState; } /** * @private * @async * Helper to make a get request to fetch next page with nextLink url and update the page iterator instance with the returned response * @returns A promise that resolves to a response data with next page collection */ async fetchNextPage() { this.pagingState = "InterpageIteration"; const nextLink = this.getOdataNextLink(); const deltaLink = this.getOdataDeltaLink(); if (!nextLink && !deltaLink) { throw new Error("NextLink and DeltaLink are undefined, Please provide a valid nextLink or deltaLink"); } const requestInformation = new RequestInformation(); requestInformation.httpMethod = HttpMethod.GET; requestInformation.urlTemplate = nextLink !== null && nextLink !== void 0 ? nextLink : deltaLink; if (this.options) { if (this.options.headers) { requestInformation.headers.addAll(this.options.headers); } if (this.options.requestOption) { requestInformation.addRequestOptions(this.options.requestOption); } } return await this.requestAdapter.send(requestInformation, this.parsableFactory, this.errorMappings); } /** * @public * @async * To resume the iteration * Note: This internally calls the iterate method, It's just for more readability. */ async resume() { return this.iterate(); } /** * @private * Iterates over a collection by enqueuing entries one by one and kicking the callback with the enqueued entry * @returns A boolean indicating the continue flag to process next page */ enumeratePage() { var _a; this.pagingState = "IntrapageIteration"; let keepIterating = true; const pageItems = (_a = this.currentPage) === null || _a === void 0 ? void 0 : _a.value; // pageItems should never be undefined at this point if (!pageItems) { throw new Error("Page items are undefined, Please provide a valid page items"); } if (pageItems.length === 0) { return true; } // continue iterating from cursor for (let i = this.cursor; i < pageItems.length; i++) { keepIterating = this.callback(pageItems[i]); this.cursor = i + 1; if (!keepIterating) { this.pagingState = "Paused"; break; } } return keepIterating; } } //# sourceMappingURL=PageIterator.js.map