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
Add PageStreamer to make it simple to fetch paged lists #654
Conversation
/// to provide another request. (The provider may build a new object, or modify the existing request.)</param> | ||
/// <param name="responseFetcher">A function to fetch a response containing a page of results given a request.</param> | ||
/// <returns>A sequence of resources, which are fetched a page at a time. Must not be null.</returns> | ||
public IEnumerable<TResource> Fetch(TRequest initialRequest, Func<TRequest, TResponse> responseFetcher) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Also, for semantics of async fetch: in addition to the 2 options you provided, don't you think we also want a 3rd option: asynchronously fetch them one by one. Kind of like This option is important when you can't store all resources in memory at once, so you have to load them one by one, in async way. |
That 3rd option is what we would have if we added the dependency to Ix-Async, so we could return an We can potentially introduce a separate project which depends on both Ix-Async and this project, and adds extension methods to |
I definitely would NOT take dependence on |
Which of the 16 overloads of ExecuteQuerySegmentedAsync are you referring to? The point of |
Btw, one downside of this PR compared with the original code is that this was originally written with the expectation of it being called by generated code, mostly. But here's an example of showing the same sort of thing in manual code: (It's possible that the lambda expression could be replaced by a method group conversion. I haven't checked.) |
Ohh, I see you point now about "The point of PageStreamer is to avoid the caller having to deal with the continuation token themselves at all". I agree that "they can just call the existing API in a loop" and that |
Right - I believe we're already good with that. In particular, if the token isn't exposed, we wouldn't be able to construct the PageStreamer to start with :) Sounds like we're on the same page now, no pun intended. Would love Ix-Async to be available already - with C# language support, ideally... (The gRPC C# tooling already has a dependency on it, btw.) |
Just had another thought about this - as in this location |
Yep. 👍 As for Async-Rx: yes, Bart De Smet was promising it to us a long time ago. Can't wait for that to happen. There is also a new kid on the block: coreclr team it prototyping with a new Async Channels and AsyncEnumerator |
Humbug - can't do that, as @peleyal If I were to move |
@@ -0,0 +1,137 @@ | |||
// Copyright 2015 Google Inc. All Rights Reserved. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
I only reviewed the PageStreamer (not tests yet). |
Due to the scale of the changes, I've now squashed and repushed. The good news is that it's now significantly easier to call, and slightly easier to construct. For example, the GCS client code listing buckets would be: private static readonly PageStreamer<Bucket, BucketsResource.ListRequest, Buckets, string> bucketPageStreamer =
new PageStreamer<Bucket, BucketsResource.ListRequest, Buckets, string>(
(request, token) => { request.PageToken = token; return request; },
buckets => buckets.NextPageToken,
buckets => buckets.Items);
...
// Create the initial request as before, then use the page streamer synchronously
// or asynchronously.
var request = ...;
foreach (var bucket in bucketPageStreamer.Fetch(request))
{
...
}
// Or
var buckets = await bucketPageStreamer.FetchAllAsync(request, cancellationToken); |
lgtm |
using Google.Apis.Requests; | ||
using Google.Apis.Discovery; | ||
using Google.Apis.Services; | ||
using System.IO; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Fixed using directive order, updated copyright year and added a TODO for a doc comment example. |
|
||
internal Request WithToken(string token) | ||
{ | ||
return new Request(resource) { Token = token, Check = Check }; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
I've rebased this to Matt's reorganization, and squashed it down to a single commit. I believe it's all sensible... |
@mmdriley @peleyal Please review the latest commit carefully (before I squash...) While rewriting the tests slightly, it struck me that within the context of google-api-dotnet-client, it's reasonable to assume that all requests objects are mutable, and so simplify the "provide a request object with this page token" to "just modify the existing request". This is basically what people would be doing anyway, and now it's unambiguous. The setup code is now simplified to:
|
{ | ||
private static readonly PageStreamedResource simpleResource = new PageStreamedResource( | ||
"simple", | ||
new Page(null, 1, 2, 3), |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
LGTM, thanks Jon! |
LGTM. Sorry again for pulling the code out from under you mid-PR. |
@mmdriley: No problem at all. Given that this was just new code, it was probably the simplest possible change to make under that scenario :) Will squash and merge. |
Fixes issue googleapis#632, as far as we want to for now. This will only make the PageStreamer available - it won't be used in generated code. We will want to add examples of how to use this. Note that the only async option for the moment is to retrieve a whole list asynchronously. While it would be nice to do this more lazily, that would need something like Ix-Async, and we'd prefer not to introduce a new dependency for this at the moment.
Add PageStreamer to make it simple to fetch paged lists
Fixes issue #632, as far as we want to for now.
This will only make the PageStreamer available - it won't be used in generated code.
We will want to add examples of how to use this.
Note that the only async option for the moment is to retrieve a whole list asynchronously.
While it would be nice to do this more lazily, that would need something like Ix-Async, and we'd prefer not to
introduce a new dependency for this at the moment.