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

ClientModel: Pageable abstractions for third-party clients #44026

Merged
merged 70 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
54f822b
Add async and sync enumerable client results
annelo-msft Apr 12, 2024
d239e17
Implement IAsyncDisposable
annelo-msft Apr 15, 2024
115295a
Merge remote-tracking branch 'upstream/main' into clientmodel-asyncen…
annelo-msft Apr 19, 2024
3b12f1f
Remove constrant and disposable; update ClientResult so response can …
annelo-msft Apr 19, 2024
dbf18ad
rename and upate tests
annelo-msft Apr 20, 2024
a798fd9
Merge remote-tracking branch 'upstream/main' into clientmodel-asyncen…
annelo-msft May 1, 2024
72951b9
Merge remote-tracking branch 'upstream/main' into clientmodel-asyncen…
annelo-msft May 2, 2024
63e1351
initial addition of files from https://github.com/joseharriaga/openai…
annelo-msft May 2, 2024
f604598
make it build
annelo-msft May 2, 2024
d3bd6b8
hello world test
annelo-msft May 2, 2024
3fca028
bootstrap more tests
annelo-msft May 2, 2024
4ea146d
more internal tests
annelo-msft May 2, 2024
262c78d
adding enumerator tests; haven't figured out the batch piece yet
annelo-msft May 2, 2024
984499d
Make batch test pass
annelo-msft May 2, 2024
f26a89b
remove collection-event functionality and add tests for public type
annelo-msft May 3, 2024
647f1a9
reshuffle
annelo-msft May 3, 2024
3189fb3
Add mock convenience SSE type to give POC of lazy request sending
annelo-msft May 3, 2024
1a0c861
add tests of delayed request
annelo-msft May 3, 2024
d5cbc8e
Add BinaryData factory method
annelo-msft May 3, 2024
2d71562
Merge remote-tracking branch 'upstream/main' into clientmodel-sse-nod…
annelo-msft May 6, 2024
0beaeea
remove funcs for creating enumerators
annelo-msft May 6, 2024
fc84db1
renames
annelo-msft May 6, 2024
5a1bd13
postpone call to protocol method from convenience APIs
annelo-msft May 6, 2024
75e3e8a
implement IAsyncDisposable correctly
annelo-msft May 6, 2024
80e6ee5
initial pass over cancellation token
annelo-msft May 6, 2024
c27581d
Per FDG, throw OperationCanceledException if cancellation token is ca…
annelo-msft May 6, 2024
a04f543
remove factory method taking Func<T> and provide example of layering …
annelo-msft May 6, 2024
d6d4375
rename internal types and WIP adding reader tests
annelo-msft May 7, 2024
6fa96cb
nits
annelo-msft May 7, 2024
1fbd038
parameterize terminal event; TBD to provide virtual method on collect…
annelo-msft May 7, 2024
f577d2e
Merge remote-tracking branch 'upstream/main' into clientmodel-sse-nod…
annelo-msft May 7, 2024
f342162
WIP: nits
annelo-msft May 7, 2024
4ac87a2
WIP: added concatenation of data lines per SSE spec
annelo-msft May 8, 2024
dab0852
updates and bug fixes
annelo-msft May 8, 2024
1941f2c
add tests and update per SSE spec
annelo-msft May 8, 2024
dee2173
Merge remote-tracking branch 'upstream/main' into clientmodel-sse-nod…
annelo-msft May 8, 2024
58ac2a3
WIP: refactor to reuse field processing across sync and async methods
annelo-msft May 9, 2024
20a3b81
Merge remote-tracking branch 'upstream/main' into clientmodel-sse-nod…
annelo-msft May 9, 2024
88d5da1
make look a little more like the BCL type proposal
annelo-msft May 9, 2024
d2776d8
simplify field implementation a bit
annelo-msft May 9, 2024
2758377
cosmetic reworking of creating an event from a pending event
annelo-msft May 9, 2024
eae0caa
Remove factory method from public API; move MockSseClient to Tests.In…
annelo-msft May 9, 2024
b8f70f7
update API; reimplement mock client implementations without internal …
annelo-msft May 9, 2024
a592c2c
Add sync client result collection abstraction
annelo-msft May 9, 2024
88de121
tidy up and add tests
annelo-msft May 10, 2024
3bf665b
add default constructor to ClientResult
annelo-msft May 10, 2024
f87933e
more tidy-up
annelo-msft May 10, 2024
43dbbc2
rename and add refdocs
annelo-msft May 10, 2024
caebaea
comments
annelo-msft May 10, 2024
46f3067
Add pageables
annelo-msft May 11, 2024
119a357
add ClientPage<T>
annelo-msft May 13, 2024
52fa4fa
pageables implement enumerators
annelo-msft May 13, 2024
d98bfa6
give page a response constructor
annelo-msft May 13, 2024
02d70f1
Merge remote-tracking branch 'upstream/main' into clientmodel-3p-page…
annelo-msft May 14, 2024
0cfb0b2
updates post merging main branch
annelo-msft May 14, 2024
08ffb83
Add hello world test for pageable collections
annelo-msft May 15, 2024
209d468
wip: tests
annelo-msft May 15, 2024
c355f8e
Merge remote-tracking branch 'upstream/main' into clientmodel-3p-page…
annelo-msft May 15, 2024
e92091e
some API updates
annelo-msft May 15, 2024
94fae1d
make page non-abstract
annelo-msft May 15, 2024
b0de24c
add test for continuation token
annelo-msft May 15, 2024
329c709
add tests for async pageable
annelo-msft May 15, 2024
a1cf4d9
remove nonnull constraint from T on pageables
annelo-msft May 15, 2024
364d6bd
add comments to public types
annelo-msft May 15, 2024
12381ff
thread through response updates
annelo-msft May 15, 2024
948e69a
export API
annelo-msft May 15, 2024
2f0c30c
update comments per pr fb
annelo-msft May 15, 2024
607f905
Expose factory method for creating ResultPage instead of constructor
annelo-msft May 16, 2024
44124b1
update CHANGELOG
annelo-msft May 16, 2024
3d37512
nit
annelo-msft May 16, 2024
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
19 changes: 19 additions & 0 deletions sdk/core/System.ClientModel/api/System.ClientModel.net6.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ public ApiKeyCredential(string key) { }
public static implicit operator System.ClientModel.ApiKeyCredential (string key) { throw null; }
public void Update(string key) { }
}
public abstract partial class AsyncPageableCollection<T> : System.ClientModel.AsyncResultCollection<T>
{
protected AsyncPageableCollection() { }
public abstract System.Collections.Generic.IAsyncEnumerable<System.ClientModel.ResultPage<T>> AsPages(string? continuationToken = null, int? pageSizeHint = default(int?));
public override System.Collections.Generic.IAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
}
public abstract partial class AsyncResultCollection<T> : System.ClientModel.ClientResult, System.Collections.Generic.IAsyncEnumerable<T>
{
protected internal AsyncResultCollection() { }
Expand Down Expand Up @@ -48,13 +54,26 @@ protected internal ClientResult(T value, System.ClientModel.Primitives.PipelineR
public virtual T Value { get { throw null; } }
public static implicit operator T (System.ClientModel.ClientResult<T> result) { throw null; }
}
public abstract partial class PageableCollection<T> : System.ClientModel.ResultCollection<T>
{
protected PageableCollection() { }
public abstract System.Collections.Generic.IEnumerable<System.ClientModel.ResultPage<T>> AsPages(string? continuationToken = null, int? pageSizeHint = default(int?));
public override System.Collections.Generic.IEnumerator<T> GetEnumerator() { throw null; }
}
public abstract partial class ResultCollection<T> : System.ClientModel.ClientResult, System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable
{
protected internal ResultCollection() { }
protected internal ResultCollection(System.ClientModel.Primitives.PipelineResponse response) { }
public abstract System.Collections.Generic.IEnumerator<T> GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
public partial class ResultPage<T> : System.ClientModel.ResultCollection<T>
{
internal ResultPage() { }
public string? ContinuationToken { get { throw null; } }
public static System.ClientModel.ResultPage<T> Create(System.Collections.Generic.IEnumerable<T> values, string? continuationToken, System.ClientModel.Primitives.PipelineResponse response) { throw null; }
public override System.Collections.Generic.IEnumerator<T> GetEnumerator() { throw null; }
}
}
namespace System.ClientModel.Primitives
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ public ApiKeyCredential(string key) { }
public static implicit operator System.ClientModel.ApiKeyCredential (string key) { throw null; }
public void Update(string key) { }
}
public abstract partial class AsyncPageableCollection<T> : System.ClientModel.AsyncResultCollection<T>
{
protected AsyncPageableCollection() { }
public abstract System.Collections.Generic.IAsyncEnumerable<System.ClientModel.ResultPage<T>> AsPages(string? continuationToken = null, int? pageSizeHint = default(int?));
public override System.Collections.Generic.IAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
}
public abstract partial class AsyncResultCollection<T> : System.ClientModel.ClientResult, System.Collections.Generic.IAsyncEnumerable<T>
{
protected internal AsyncResultCollection() { }
Expand Down Expand Up @@ -48,13 +54,26 @@ protected internal ClientResult(T value, System.ClientModel.Primitives.PipelineR
public virtual T Value { get { throw null; } }
public static implicit operator T (System.ClientModel.ClientResult<T> result) { throw null; }
}
public abstract partial class PageableCollection<T> : System.ClientModel.ResultCollection<T>
{
protected PageableCollection() { }
public abstract System.Collections.Generic.IEnumerable<System.ClientModel.ResultPage<T>> AsPages(string? continuationToken = null, int? pageSizeHint = default(int?));
public override System.Collections.Generic.IEnumerator<T> GetEnumerator() { throw null; }
}
public abstract partial class ResultCollection<T> : System.ClientModel.ClientResult, System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable
{
protected internal ResultCollection() { }
protected internal ResultCollection(System.ClientModel.Primitives.PipelineResponse response) { }
public abstract System.Collections.Generic.IEnumerator<T> GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
public partial class ResultPage<T> : System.ClientModel.ResultCollection<T>
{
internal ResultPage() { }
public string? ContinuationToken { get { throw null; } }
public static System.ClientModel.ResultPage<T> Create(System.Collections.Generic.IEnumerable<T> values, string? continuationToken, System.ClientModel.Primitives.PipelineResponse response) { throw null; }
public override System.Collections.Generic.IEnumerator<T> GetEnumerator() { throw null; }
}
}
namespace System.ClientModel.Primitives
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.ClientModel.Primitives;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace System.ClientModel;

/// <summary>
/// Represents a collection of results returned from a cloud service operation
/// sequentially over one or more calls to the service.
/// </summary>
public abstract class AsyncPageableCollection<T> : AsyncResultCollection<T>
{
/// <summary>
/// Create a new instance of <see cref="AsyncPageableCollection{T}"/>.
/// </summary>
/// <remarks>This constructor does not take a <see cref="PipelineResponse"/>
/// because derived types are expected to defer the first service call
/// until the collection is enumerated using <c>await foreach</c>.
/// </remarks>
protected AsyncPageableCollection() : base()
{
}

/// <summary>
/// Return an enumerable of <see cref="ResultPage{T}"/> that aynchronously
/// enumerates the collection's pages instead of the collection's individual
/// values. This may make multiple service requests.
/// </summary>
/// <param name="continuationToken">A token indicating where the collection
/// of results returned from the service should begin. Passing <c>null</c>
/// will start the collection at the first page of values.</param>
/// <param name="pageSizeHint">The number of items to request that the
/// service return in a <see cref="ResultPage{T}"/>, if the service supports
/// such requests.</param>
/// <returns>An async sequence of <see cref="ResultPage{T}"/>, each holding
/// the subset of collection values contained in a given service response.
/// </returns>
public abstract IAsyncEnumerable<ResultPage<T>> AsPages(string? continuationToken = default, int? pageSizeHint = default);

/// <summary>
/// Return an enumerator that iterates asynchronously through the collection
/// values. This may make multiple service requests.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used
/// with requests made while enumerating asynchronously.</param>
/// <returns>An <see cref="IAsyncEnumerator{T}"/> that can iterate
/// asynchronously through the collection values.</returns>
public override async IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
await foreach (ResultPage<T> page in AsPages().ConfigureAwait(false).WithCancellation(cancellationToken))
{
foreach (T value in page)
{
yield return value;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.ClientModel.Primitives;
using System.Collections.Generic;

namespace System.ClientModel;

/// <summary>
/// Represents a collection of results returned from a cloud service operation
/// sequentially over one or more calls to the service.
/// </summary>
public abstract class PageableCollection<T> : ResultCollection<T>
{
/// <summary>
/// Create a new instance of <see cref="PageableCollection{T}"/>.
/// </summary>
/// <remarks>This constructor does not take a <see cref="PipelineResponse"/>
/// because derived types are expected to defer the first service call
/// until the collection is enumerated using <c>foreach</c>.</remarks>
protected PageableCollection() : base()
{
}

/// <summary>
/// Return an enumerable of <see cref="ResultPage{T}"/> that enumerates the
/// collection's pages instead of the collection's individual values. This
/// may make multiple service requests.
/// </summary>
/// <param name="continuationToken">A token indicating where the collection
/// of results returned from the service should begin. Passing <c>null</c>
/// will start the collection at the first page of values.</param>
/// <param name="pageSizeHint">The number of items to request that the
/// service return in a <see cref="ResultPage{T}"/>, if the service supports
/// such requests.</param>
/// <returns>A sequence of <see cref="ResultPage{T}"/>, each holding the
/// subset of collection values contained in a given service response.
/// </returns>
public abstract IEnumerable<ResultPage<T>> AsPages(string? continuationToken = default, int? pageSizeHint = default);

/// <summary>
/// Return an enumerator that iterates through the collection values. This
/// may make multiple service requests.
/// </summary>
/// <returns>An <see cref="IEnumerator{T}"/> that can iterate through the
/// collection values.</returns>
public override IEnumerator<T> GetEnumerator()
{
foreach (ResultPage<T> page in AsPages())
{
foreach (T value in page)
{
yield return value;
}
}
}
}
50 changes: 50 additions & 0 deletions sdk/core/System.ClientModel/src/Convenience/ResultPageOfT.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.ClientModel.Primitives;
using System.Collections.Generic;

namespace System.ClientModel;

/// <summary>
/// Represents the subset (or page) of results contained in a single response
/// from a cloud service returning a collection of results sequentially over
/// one or more calls to the service (i.e. a paged collection).
/// </summary>
public class ResultPage<T> : ResultCollection<T>
{
private readonly IEnumerable<T> _values;

private ResultPage(IEnumerable<T> values, string? continuationToken, PipelineResponse response)
: base(response)
{
_values = values;
ContinuationToken = continuationToken;
}

/// <summary>
/// Creates a new <see cref="ResultPage{T}"/>.
/// </summary>
/// <param name="values">The values contained in <paramref name="response"/>.
/// </param>
/// <param name="continuationToken">The token that can be used to request
/// the next page of results from the service, or <c>null</c> if this page
/// holds the final subset of values.</param>
/// <param name="response">The <see cref="PipelineResponse"/> holding the
/// collection values returned by the service.</param>
/// <returns>An instance of <see cref="ResultPage{T}"/> holding the provided
/// values.</returns>
public static ResultPage<T> Create(IEnumerable<T> values, string? continuationToken, PipelineResponse response)
=> new(values, continuationToken, response);

/// <summary>
/// Gets the continuation token used to request the next
/// <see cref="ResultPage{T}"/>. May be <c>null</c> or empty when no values
/// remain to be returned from the collection.
/// </summary>
public string? ContinuationToken { get; }

/// <inheritdoc/>
public override IEnumerator<T> GetEnumerator()
=> _values.GetEnumerator();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace System.ClientModel.Tests.Results;

public class PipelineResponseTests
public class ClientResultTests
{
#region ClientResult

Expand Down
Loading