Skip to content

Commit 1285f1c

Browse files
authoredApr 26, 2021
Added CollectionSegment<T> (#3597)
1 parent 89a07cf commit 1285f1c

6 files changed

+188
-2
lines changed
 

‎src/HotChocolate/Core/src/Types.OffsetPagination/CollectionSegment.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
namespace HotChocolate.Types.Pagination
77
{
88
/// <summary>
9-
/// The collection segment represents one page of a pagebale data set / collection.
9+
/// The collection segment represents one page of a pageable dataset / collection.
1010
/// </summary>
1111
public class CollectionSegment : IPage
1212
{
@@ -31,7 +31,8 @@ public CollectionSegment(
3131
{
3232
Items = items ??
3333
throw new ArgumentNullException(nameof(items));
34-
Info = info;
34+
Info = info ??
35+
throw new ArgumentNullException(nameof(info));
3536
_getTotalCount = getTotalCount ??
3637
throw new ArgumentNullException(nameof(getTotalCount));
3738
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
6+
namespace HotChocolate.Types.Pagination
7+
{
8+
/// <inheritdoc />
9+
public class CollectionSegment<T> : CollectionSegment
10+
where T : class
11+
{
12+
/// <summary>
13+
/// Initializes <see cref="CollectionSegment" />.
14+
/// </summary>
15+
/// <param name="items">
16+
/// The items that belong to this page.
17+
/// </param>
18+
/// <param name="info">
19+
/// Additional information about this page.
20+
/// </param>
21+
/// <param name="getTotalCount">
22+
/// A delegate to request the the total count.
23+
/// </param>
24+
public CollectionSegment(
25+
IReadOnlyCollection<T> items,
26+
CollectionSegmentInfo info,
27+
Func<CancellationToken, ValueTask<int>> getTotalCount)
28+
: base(items, info, getTotalCount)
29+
{
30+
Items = items;
31+
}
32+
33+
/// <summary>
34+
/// The items that belong to this page.
35+
/// </summary>
36+
public new IReadOnlyCollection<T> Items { get; }
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Xunit;
4+
5+
namespace HotChocolate.Types.Pagination
6+
{
7+
public class CollectionSegmentTests
8+
{
9+
[Fact]
10+
public void CreateCollectionSegment_PageInfoAndItems_PassedCorrectly()
11+
{
12+
// arrange
13+
var pageInfo = new CollectionSegmentInfo(true, true);
14+
var items = new List<string>();
15+
16+
// act
17+
var collection = new CollectionSegment(
18+
items,
19+
pageInfo,
20+
ct => throw new NotSupportedException());
21+
22+
// assert
23+
Assert.Equal(pageInfo, collection.Info);
24+
Assert.Equal(items, collection.Items);
25+
}
26+
27+
[Fact]
28+
public void CreateCollectionSegment_PageInfoNull_ArgumentNullException()
29+
{
30+
// arrange
31+
var items = new List<string>();
32+
33+
// act
34+
Action a = () => new CollectionSegment<string>(
35+
items, null, ct => throw new NotSupportedException());
36+
37+
// assert
38+
Assert.Throws<ArgumentNullException>(a);
39+
}
40+
41+
[Fact]
42+
public void CreateCollectionSegment_ItemsNull_ArgumentNullException()
43+
{
44+
// arrange
45+
var pageInfo = new CollectionSegmentInfo(true, true);
46+
47+
// act
48+
Action a = () => new CollectionSegment<string>(
49+
null, pageInfo, ct => throw new NotSupportedException());
50+
51+
// assert
52+
Assert.Throws<ArgumentNullException>(a);
53+
}
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using HotChocolate.Execution;
4+
using HotChocolate.Tests;
5+
using Snapshooter.Xunit;
6+
using Xunit;
7+
8+
namespace HotChocolate.Types.Pagination
9+
{
10+
public class CustomCollectionSegmentHandlerTests
11+
{
12+
[Fact]
13+
public void Infer_Schema_Correctly_When_CollectionSegment_IsUsed()
14+
{
15+
SchemaBuilder.New()
16+
.AddQueryType<Query>()
17+
.Create()
18+
.Print()
19+
.MatchSnapshot();
20+
}
21+
22+
[Fact]
23+
public async Task Use_Resolver_Result_If_It_Is_A_Page()
24+
{
25+
// arrange
26+
Snapshot.FullName();
27+
28+
IReadOnlyQueryRequest request =
29+
QueryRequestBuilder.New()
30+
.SetQuery("{ items { items } }")
31+
.Create();
32+
33+
// act
34+
// assert
35+
await SchemaBuilder.New()
36+
.AddQueryType<Query>()
37+
.Create()
38+
.MakeExecutable()
39+
.ExecuteAsync(request)
40+
.MatchSnapshotAsync();
41+
}
42+
43+
public class Query
44+
{
45+
[UseOffsetPaging]
46+
public CollectionSegment<string> GetItems(int skip, int take)
47+
{
48+
return new CollectionSegment<string>(
49+
new[] { "hello", "abc" },
50+
new CollectionSegmentInfo(false, false),
51+
ct => throw new NotImplementedException());
52+
}
53+
}
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
schema {
2+
query: Query
3+
}
4+
5+
"Information about the offset pagination."
6+
type CollectionSegmentInfo {
7+
"Indicates whether more items exist following the set defined by the clients arguments."
8+
hasNextPage: Boolean!
9+
"Indicates whether more items exist prior the set defined by the clients arguments."
10+
hasPreviousPage: Boolean!
11+
}
12+
13+
type Query {
14+
items(skip: Int take: Int): StringCollectionSegment
15+
}
16+
17+
type StringCollectionSegment {
18+
items: [String]
19+
"Information to aid in pagination."
20+
pageInfo: CollectionSegmentInfo!
21+
}
22+
23+
"The `@defer` directive may be provided for fragment spreads and inline fragments to inform the executor to delay the execution of the current fragment to indicate deprioritization of the current fragment. A query with `@defer` directive will cause the request to potentially return multiple responses, where non-deferred data is delivered in the initial response and data deferred is delivered in a subsequent response. `@include` and `@skip` take precedence over `@defer`."
24+
directive @defer("If this argument label has a value other than null, it will be passed on to the result of this defer directive. This label is intended to give client applications a way to identify to which fragment a deferred result belongs to." label: String "Deferred when true." if: Boolean) on FRAGMENT_SPREAD | INLINE_FRAGMENT
25+
26+
"The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such as asynchronous iterators to provide a partial list in the initial response, and additional list items in subsequent responses. `@include` and `@skip` take precedence over `@stream`."
27+
directive @stream("If this argument label has a value other than null, it will be passed on to the result of this stream directive. This label is intended to give client applications a way to identify to which fragment a streamed result belongs to." label: String "The initial elements that shall be send down to the consumer." initialCount: Int! "Streamed when true." if: Boolean!) on FIELD
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"data": {
3+
"items": {
4+
"items": [
5+
"hello",
6+
"abc"
7+
]
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)
Please sign in to comment.