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

Async Iterator Updates #3005

Merged
merged 1 commit into from
Apr 20, 2024
Merged
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
71 changes: 0 additions & 71 deletions docs/graph/behaviors.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,77 +30,6 @@ await graph.users();

> DefaultInit and DefaultHeaders are separated to make it easier to create your own default headers or init behavior. You should include both if composing your own default behavior.

## Paged

_Added in 3.4.0_

The Paged behavior allows you to access the information in a collection through a series of pages. While you can use it directly, you will likely use the `paged` method of the collections which handles things for you.

> Note that not all entity types support `count` and where it is unsupported it will return 0.

Basic example, read all users:

```TypeScript
import { graphfi, DefaultHeaders } from "@pnp/graph";
import "@pnp/graph/users";

const graph = graphfi().using(DefaultHeaders());

const allUsers = [];
let users = await graph.users.top(300).paged();

allUsers.push(...users.value);

while (users.hasNext) {
users = await users.next();
allUsers.push(...users.value);
}

console.log(`All users: ${JSON.stringify(allUsers)}`);
```

Beyond the basics other query operations are supported such as filter and select.

```TypeScript
import { graphfi, DefaultHeaders } from "@pnp/graph";
import "@pnp/graph/users";

const graph = graphfi().using(DefaultHeaders());

const allUsers = [];
let users = await graph.users.top(50).select("userPrincipalName", "displayName").filter("startswith(displayName, 'A')").paged();

allUsers.push(...users.value);

while (users.hasNext) {
users = await users.next();
allUsers.push(...users.value);
}

console.log(`All users: ${JSON.stringify(allUsers)}`);
```

And similarly for groups, showing the same pattern for different types of collections

```TypeScript
import { graphfi, DefaultHeaders } from "@pnp/graph";
import "@pnp/graph/groups";

const graph = graphfi().using(DefaultHeaders());

const allGroups = [];
let groups = await graph.groups.paged();

allGroups.push(...groups.value);

while (groups.hasNext) {
groups = await groups.next();
allGroups.push(...groups.value);
}

console.log(`All groups: ${JSON.stringify(allGroups)}`);
```

## Endpoint

This behavior is used to change the endpoint to which requests are made, either "beta" or "v1.0". This allows you to easily switch back and forth between the endpoints as needed.
Expand Down
37 changes: 10 additions & 27 deletions docs/sp/items.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ console.log(items2);

### Get Paged Items

Working with paging can be a challenge as it is based on skip tokens and item ids, something that is hard to guess at runtime. To simplify things you can use the getPaged method on the Items class to assist. Note that there isn't a way to move backwards in the collection, this is by design. The pattern you should use to support backwards navigation in the results is to cache the results into a local array and use the standard array operators to get previous pages. Alternatively you can append the results to the UI, but this can have performance impact for large result sets.
Working with paging can be a challenge as it is based on skip tokens and item ids, something that is hard to guess at runtime. To simplify things you can use the new Async Iterator functionality on the Items class to assist.

```TypeScript
import { spfi } from "@pnp/sp";
Expand All @@ -41,35 +41,18 @@ import "@pnp/sp/items";

const sp = spfi(...);

// basic case to get paged items form a list
const items = await sp.web.lists.getByTitle("BigList").items.getPaged();

// you can also provide a type for the returned values instead of any
const items = await sp.web.lists.getByTitle("BigList").items.getPaged<{Title: string}[]>();

// the query also works with select to choose certain fields and top to set the page size
const items = await sp.web.lists.getByTitle("BigList").items.select("Title", "Description").top(50).getPaged<{Title: string}[]>();

// the results object will have two properties and one method:

// the results property will be an array of the items returned
if (items.results.length > 0) {
console.log("We got results!");

for (let i = 0; i < items.results.length; i++) {
// type checking works here if we specify the return type
console.log(items.results[i].Title);
}
// Using async iterator to loop through pages of items in a large list
for await (const items of sp.web.lists.getByTitle("BigList").items()) {
console.log(items);
break; // closes the iterator, returns
}

// the hasNext property is used with the getNext method to handle paging
// hasNext will be true so long as there are additional results
if (items.hasNext) {
//using async iterator in combination with top() to get pages of items in chunks of 10
for await (const items of sp.web.lists.getByTitle("BigList").items.top(10)) {
console.log(items);
break; // closes the iterator, returns
}

// this will carry over the type specified in the original query for the results array
items = await items.getNext();
console.log(items.results.length);
}
```

### getListItemChangesSinceToken
Expand Down
2 changes: 2 additions & 0 deletions docs/transition-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ As an updated pattern we are recommending you move to an async iterator pattern
With that in mind we've removed the `/items/get-all` endpoint. In addition we've updated the @pnp/sp package's `IItems` and `_Items` collections as well as the @pnp/graph `IGraphQueryableCollection` to support the async iterator pattern.

Check out this example for more information on this pattern: [Get Paged Items](./sp/items.md#get-paged-items).

For advanced async patterns: [Async Paging](./concepts/async-paging.md).