Skip to content

Commit

Permalink
[Storage][File] Add paged async iterator for FileClient listHan… (#5536)
Browse files Browse the repository at this point in the history
Resolves #5530.
  • Loading branch information
jeremymeng authored Oct 15, 2019
1 parent b69c611 commit f2850e1
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 3 deletions.
104 changes: 103 additions & 1 deletion sdk/storage/storage-file/src/FileClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import {
FILE_RANGE_MAX_SIZE_BYTES,
DEFAULT_HIGH_LEVEL_PARALLELISM
} from "./utils/constants";
import "@azure/core-paging";
import { PageSettings, PagedAsyncIterableIterator } from "@azure/core-paging";
import { Credential } from "./credentials/Credential";
import { Batch } from "./utils/Batch";
import { BufferScheduler } from "./utils/BufferScheduler";
Expand Down Expand Up @@ -445,6 +447,17 @@ export interface FileListHandlesSegmentOptions extends CommonOptions {
maxresults?: number;
}

export interface FileListHandlesOptions extends CommonOptions {
/**
* An implementation of the `AbortSignalLike` interface to signal the request to cancel the operation.
* For example, use the @azure/abort-controller to create an `AbortSignal`.
*
* @type {AbortSignalLike}
* @memberof FileClearRangeOptions
*/
abortSignal?: AbortSignalLike;
}

/**
* Options to configure File - File Force Close Handles Options.
*
Expand Down Expand Up @@ -1819,7 +1832,7 @@ export class FileClient extends StorageClient {
* @returns {Promise<Models.FileListHandlesResponse>}
* @memberof FileURL
*/
public async listHandlesSegment(
private async listHandlesSegment(
marker?: string,
options: FileListHandlesSegmentOptions = {}
): Promise<Models.FileListHandlesResponse> {
Expand Down Expand Up @@ -1850,6 +1863,95 @@ export class FileClient extends StorageClient {
}
}

/**
* Returns an AsyncIterableIterator for FileListHandlesResponse
*
* @private
* @param {string} [marker] A string value that identifies the portion of the list to be
* returned with the next list handles operation. The operation returns a
* marker value within the response body if the list returned was not complete.
* The marker value may then be used in a subsequent call to request the next
* set of list items.
* @param {FileListHandlesSegmentOptions} [options] Options to list handles operation.
* @returns {AsyncIterableIterator<Models.FileListHandlesResponse>}
* @memberof FileClient
*/
private async *iterateHandleSegments(
marker?: string,
options: FileListHandlesSegmentOptions = {}
): AsyncIterableIterator<Models.FileListHandlesResponse> {
let listHandlesResponse;
if (!!marker || marker === undefined) {
do {
listHandlesResponse = await this.listHandlesSegment(marker, options);
marker = listHandlesResponse.nextMarker;
yield listHandlesResponse;
} while (marker);
}
}

/**
* Returns an AsyncIterableIterator for handles
*
* @private
* @param {FileListHandlesSegmentOptions} [options] Options to list handles operation.
* @returns {AsyncIterableIterator<Models.HandleItem>}
* @memberof FileClient
*/
private async *listHandleItems(
options: FileListHandlesSegmentOptions = {}
): AsyncIterableIterator<Models.HandleItem> {
let marker: string | undefined;
for await (const listHandlesResponse of this.iterateHandleSegments(marker, options)) {
if (listHandlesResponse.handleList) {
for (const handle of listHandlesResponse.handleList) {
yield handle;
}
}
}
}

/**
* Returns an async iterable iterator to list all the handles.
* under the specified account.
*
* .byPage() returns an async iterable iterator to list the handles in pages.
*
* @param {FileListHandlesOptions} [options] Options to list handles operation.
* @memberof FileClient
* @returns {PagedAsyncIterableIterator<Models.HandleItem, Models.FileListHandlesResponse>}
* An asyncIterableIterator that supports paging.
*/
public listHandles(
options: FileListHandlesOptions = {}
): PagedAsyncIterableIterator<Models.HandleItem, Models.FileListHandlesResponse> {
// an AsyncIterableIterator to iterate over handles
const iter = this.listHandleItems(options);
return {
/**
* @member {Promise} [next] The next method, part of the iteration protocol
*/
async next() {
return iter.next();
},
/**
* @member {Symbol} [asyncIterator] The connection to the async iterator, part of the iteration protocol
*/
[Symbol.asyncIterator]() {
return this;
},
/**
* @member {Function} [byPage] Return an AsyncIterableIterator that works a page at a time
*/
byPage: (settings: PageSettings = {}) => {
return this.iterateHandleSegments(settings.continuationToken, {
maxresults: settings.maxPageSize,
...options
});
}
};
}

/**
* Force close all handles for a file.
* @see https://docs.microsoft.com/en-us/rest/api/storageservices/force-close-handles
Expand Down
10 changes: 8 additions & 2 deletions sdk/storage/storage-file/test/fileclient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,10 @@ describe("FileClient", () => {
it("listHandles should work", async () => {
await fileClient.create(10);

const result = await fileClient.listHandlesSegment(undefined);
const result = (await fileClient
.listHandles()
.byPage()
.next()).value;
if (result.handleList !== undefined && result.handleList.length > 0) {
const handle = result.handleList[0];
assert.notDeepStrictEqual(handle.handleId, undefined);
Expand Down Expand Up @@ -493,7 +496,10 @@ describe("FileClient", () => {

// TODO: Open or create a handle

const result = await fileClient.listHandlesSegment(undefined);
const result = (await fileClient
.listHandles()
.byPage()
.next()).value;
if (result.handleList !== undefined && result.handleList.length > 0) {
const handle = result.handleList[0];
await dirClient.forceCloseHandle(handle.handleId);
Expand Down

0 comments on commit f2850e1

Please sign in to comment.