Skip to content

Commit 35c8091

Browse files
authored
Added Data API refinements. (#7966)
1 parent 4f57d9a commit 35c8091

File tree

7 files changed

+140
-16
lines changed

7 files changed

+140
-16
lines changed

src/GreenDonut/src/GreenDonut.Data.Primitives/SortBy.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,29 @@ public IOrderedQueryable<TEntity> ApplyThenBy(IOrderedQueryable<TEntity> queryab
8181
}
8282
}
8383

84+
/// <summary>
85+
/// Provides factory methods for creating sort operations.
86+
/// </summary>
87+
/// <typeparam name="TEntity">
88+
/// The entity type associated with the sort operation.
89+
/// </typeparam>
8490
public static class SortBy<TEntity>
8591
{
92+
/// <summary>
93+
/// Creates a sort operation that sorts in ascending order.
94+
/// </summary>
95+
/// <param name="keySelector">
96+
/// The field on which the sort operation is applied.
97+
/// </param>
98+
/// <typeparam name="TValue">
99+
/// The type of the field on which the sort operation is applied.
100+
/// </typeparam>
101+
/// <returns>
102+
/// A sort operation that sorts in ascending order.
103+
/// </returns>
104+
/// <exception cref="ArgumentNullException">
105+
/// <paramref name="keySelector"/> is <c>null</c>.
106+
/// </exception>
86107
public static SortBy<TEntity, TValue> Ascending<TValue>(
87108
Expression<Func<TEntity, TValue>> keySelector)
88109
{
@@ -94,6 +115,21 @@ public static SortBy<TEntity, TValue> Ascending<TValue>(
94115
return new SortBy<TEntity, TValue>(keySelector, true);
95116
}
96117

118+
/// <summary>
119+
/// Creates a sort operation that sorts in descending order.
120+
/// </summary>
121+
/// <param name="keySelector">
122+
/// The field on which the sort operation is applied.
123+
/// </param>
124+
/// <typeparam name="TValue">
125+
/// The type of the field on which the sort operation is applied.
126+
/// </typeparam>
127+
/// <returns>
128+
/// A sort operation that sorts in descending order.
129+
/// </returns>
130+
/// <exception cref="ArgumentNullException">
131+
/// <paramref name="keySelector"/> is <c>null</c>.
132+
/// </exception>
97133
public static SortBy<TEntity, TValue> Descending<TValue>(
98134
Expression<Func<TEntity, TValue>> keySelector)
99135
{

src/GreenDonut/src/GreenDonut.Data.Primitives/SortDefinition.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Immutable;
2+
using System.Linq.Expressions;
23
using System.Text;
34

45
namespace GreenDonut.Data;
@@ -47,6 +48,60 @@ public SortDefinition(IEnumerable<ISortBy<T>> operations)
4748
public void Deconstruct(out ImmutableArray<ISortBy<T>> operations)
4849
=> operations = Operations;
4950

51+
/// <summary>
52+
/// Adds a sort operation to the definition.
53+
/// </summary>
54+
/// <param name="keySelector">
55+
/// The field on which the sort operation is applied.
56+
/// </param>
57+
/// <typeparam name="TResult">
58+
/// The type of the field on which the sort operation is applied.
59+
/// </typeparam>
60+
/// <returns>
61+
/// The updated sort definition.
62+
/// </returns>
63+
public SortDefinition<T> AddAscending<TResult>(
64+
Expression<Func<T, TResult>> keySelector)
65+
{
66+
if (keySelector == null)
67+
{
68+
throw new ArgumentNullException(nameof(keySelector));
69+
}
70+
71+
var operations = Operations.Add(SortBy<T>.Ascending(keySelector));
72+
return new SortDefinition<T>(operations);
73+
}
74+
75+
/// <summary>
76+
/// Adds a descending sort operation to the definition.
77+
/// </summary>
78+
/// <param name="keySelector">
79+
/// The field on which the sort operation is applied.
80+
/// </param>
81+
/// <typeparam name="TResult">
82+
/// The type of the field on which the sort operation is applied.
83+
/// </typeparam>
84+
/// <returns>
85+
/// The updated sort definition.
86+
/// </returns>
87+
public SortDefinition<T> AddDescending<TResult>(
88+
Expression<Func<T, TResult>> keySelector)
89+
{
90+
if (keySelector == null)
91+
{
92+
throw new ArgumentNullException(nameof(keySelector));
93+
}
94+
95+
var operations = Operations.Add(SortBy<T>.Ascending(keySelector));
96+
return new SortDefinition<T>(operations);
97+
}
98+
99+
/// <summary>
100+
/// Returns a string representation of the sort definition.
101+
/// </summary>
102+
/// <returns>
103+
/// A string representation of the sort definition.
104+
/// </returns>
50105
public override string ToString()
51106
{
52107
if (Operations.Length == 0)

src/GreenDonut/src/GreenDonut.Data/Extensions/GreenDonutPaginationBatchingDataLoaderExtensions.cs

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,19 @@ public static IDataLoader<TKey, Page<TValue>> WithPagingArguments<TKey, TValue>(
3838
this IDataLoader<TKey, Page<TValue>> dataLoader,
3939
PagingArguments pagingArguments)
4040
where TKey : notnull
41-
=> With(dataLoader, pagingArguments);
41+
=> WithInternal(dataLoader, pagingArguments, null);
4242

4343
/// <summary>
4444
/// Branches a DataLoader with the provided <see cref="PagingArguments"/>.
4545
/// </summary>
4646
/// <param name="dataLoader">
47-
/// The DataLoader that shall be branched.
47+
/// The DataLoader that shall be branched.
4848
/// </param>
4949
/// <param name="pagingArguments">
50-
/// The paging arguments that shall exist as state in the branched DataLoader.
50+
/// The paging arguments that shall exist as state in the branched DataLoader.
5151
/// </param>
5252
/// <param name="context">
53-
/// The query context that shall exist as state in the branched DataLoader.
53+
/// The query context that shall exist as state in the branched DataLoader.
5454
/// </param>
5555
/// <typeparam name="TKey">
5656
/// The key type of the DataLoader.
@@ -64,11 +64,17 @@ public static IDataLoader<TKey, Page<TValue>> WithPagingArguments<TKey, TValue>(
6464
/// <exception cref="ArgumentNullException">
6565
/// Throws if the <paramref name="dataLoader"/> is <c>null</c>.
6666
/// </exception>
67-
public static IDataLoader<TKey, Page<TValue>> With<TKey, TValue>(
68-
this IDataLoader<TKey, Page<TValue>> dataLoader,
67+
public static IDataLoader<TKey, Page<TValue>> With<TKey, TValue>(this IDataLoader<TKey, Page<TValue>> dataLoader,
6968
PagingArguments pagingArguments,
7069
QueryContext<TValue>? context = null)
7170
where TKey : notnull
71+
=> WithInternal(dataLoader, pagingArguments, context);
72+
73+
private static IDataLoader<TKey, Page<TValue>> WithInternal<TKey, TValue>(
74+
this IDataLoader<TKey, Page<TValue>> dataLoader,
75+
PagingArguments pagingArguments,
76+
QueryContext<TValue>? context)
77+
where TKey : notnull
7278
{
7379
if (dataLoader is null)
7480
{
@@ -160,7 +166,8 @@ public static IDataLoader<TKey, Page<TValue>> Select<TElement, TKey, TValue>(
160166

161167
var branchKey = selector.ComputeHash();
162168
var state = new QueryState(DataLoaderStateKeys.Selector, new DefaultSelectorBuilder(selector));
163-
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch, state);
169+
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch,
170+
state);
164171
}
165172

166173
/// <summary>
@@ -200,11 +207,34 @@ public static IDataLoader<TKey, Page<TValue>> Where<TKey, TValue>(
200207
}
201208

202209
var branchKey = predicate.ComputeHash();
203-
var state = new QueryState(DataLoaderStateKeys.Predicate, GetOrCreateBuilder(dataLoader.ContextData, predicate));
204-
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch, state);
210+
var state = new QueryState(DataLoaderStateKeys.Predicate,
211+
GetOrCreateBuilder(dataLoader.ContextData, predicate));
212+
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch,
213+
state);
205214
}
206215

207-
public static IDataLoader<TKey, Page<TValue>> Order<TKey, TValue>(
216+
/// <summary>
217+
/// Adds a sorting definition as state to the DataLoader.
218+
/// </summary>
219+
/// <param name="dataLoader">
220+
/// The DataLoader.
221+
/// </param>
222+
/// <param name="sortDefinition">
223+
/// The sorting definition that shall be added as state to the DataLoader.
224+
/// </param>
225+
/// <typeparam name="TKey">
226+
/// The key type of the DataLoader.
227+
/// </typeparam>
228+
/// <typeparam name="TValue">
229+
/// The value type of the DataLoader.
230+
/// </typeparam>
231+
/// <returns>
232+
/// Returns the DataLoader with the added projection.
233+
/// </returns>
234+
/// <exception cref="ArgumentNullException">
235+
/// Throws if the <paramref name="dataLoader"/> is <c>null</c>.
236+
/// </exception>
237+
public static IDataLoader<TKey, Page<TValue>> OrderBy<TKey, TValue>(
208238
this IDataLoader<TKey, Page<TValue>> dataLoader,
209239
SortDefinition<TValue>? sortDefinition)
210240
where TKey : notnull
@@ -221,10 +251,11 @@ public static IDataLoader<TKey, Page<TValue>> Order<TKey, TValue>(
221251

222252
var branchKey = sortDefinition.ComputeHash();
223253
var state = new QueryState(DataLoaderStateKeys.Sorting, sortDefinition);
224-
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch, state);
254+
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch,
255+
state);
225256
}
226257

227-
private static string ComputeHash<T>(this PagingArguments arguments, QueryContext<T>? context = null)
258+
private static string ComputeHash<T>(this PagingArguments arguments, QueryContext<T>? context)
228259
{
229260
var hasher = ExpressionHasherPool.Shared.Get();
230261

src/GreenDonut/src/GreenDonut.Data/Extensions/GreenDonutQueryableExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> queryable
321321
/// <exception cref="ArgumentNullException">
322322
/// Throws if <paramref name="queryable"/> is <c>null</c> or if <paramref name="queryContext"/> is <c>null</c>.
323323
/// </exception>
324-
public static IQueryable<T> Apply<T>(
324+
public static IQueryable<T> With<T>(
325325
this IQueryable<T> queryable,
326326
QueryContext<T>? queryContext,
327327
Func<SortDefinition<T>, SortDefinition<T>>? modifySortDefinition = null)

src/GreenDonut/src/GreenDonut/Result.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,6 @@ public static implicit operator TValue(Result<TValue> result)
108108
=> result.Value;
109109
}
110110

111+
#pragma warning disable RCS1194
111112
public class KeyNotFoundException(string message) : Exception(message);
113+
#pragma warning restore RCS1194

src/HotChocolate/Data/src/Data/Filters/Extensions/HotChocolateExecutionDataLoaderExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,6 @@ public static IDataLoader<TKey, Page<TValue>> Order<TKey, TValue>(
150150
where TKey : notnull
151151
{
152152
var definition = context.AsSortDefinition<TValue>();
153-
return dataLoader.Order(definition);
153+
return dataLoader.OrderBy(definition);
154154
}
155155
}

src/HotChocolate/Data/test/Data.Tests/IntegrationTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,7 +1196,7 @@ public IQueryable<Author> GetAuthorsData(QueryContext<Author> context)
11961196
Books = new List<Book>()
11971197
},
11981198
}.AsQueryable()
1199-
.Apply(context);
1199+
.With(context);
12001200

12011201
[UseSorting]
12021202
public IQueryable<Author> GetAuthorsData2(QueryContext<Author> context)
@@ -1221,6 +1221,6 @@ public IQueryable<Author> GetAuthorsData2(QueryContext<Author> context)
12211221
Books = new List<Book>()
12221222
}
12231223
}.AsQueryable()
1224-
.Apply(context, t => t with { Operations = t.Operations.Add(SortBy<Author>.Ascending(t => t.Id)) });
1224+
.With(context, t => t with { Operations = t.Operations.Add(SortBy<Author>.Ascending(t => t.Id)) });
12251225
}
12261226
}

0 commit comments

Comments
 (0)