Skip to content

Commit

Permalink
Added Data API refinements. (#7966)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib authored Jan 29, 2025
1 parent 4f57d9a commit 35c8091
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 16 deletions.
36 changes: 36 additions & 0 deletions src/GreenDonut/src/GreenDonut.Data.Primitives/SortBy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,29 @@ public IOrderedQueryable<TEntity> ApplyThenBy(IOrderedQueryable<TEntity> queryab
}
}

/// <summary>
/// Provides factory methods for creating sort operations.
/// </summary>
/// <typeparam name="TEntity">
/// The entity type associated with the sort operation.
/// </typeparam>
public static class SortBy<TEntity>
{
/// <summary>
/// Creates a sort operation that sorts in ascending order.
/// </summary>
/// <param name="keySelector">
/// The field on which the sort operation is applied.
/// </param>
/// <typeparam name="TValue">
/// The type of the field on which the sort operation is applied.
/// </typeparam>
/// <returns>
/// A sort operation that sorts in ascending order.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="keySelector"/> is <c>null</c>.
/// </exception>
public static SortBy<TEntity, TValue> Ascending<TValue>(
Expression<Func<TEntity, TValue>> keySelector)
{
Expand All @@ -94,6 +115,21 @@ public static SortBy<TEntity, TValue> Ascending<TValue>(
return new SortBy<TEntity, TValue>(keySelector, true);
}

/// <summary>
/// Creates a sort operation that sorts in descending order.
/// </summary>
/// <param name="keySelector">
/// The field on which the sort operation is applied.
/// </param>
/// <typeparam name="TValue">
/// The type of the field on which the sort operation is applied.
/// </typeparam>
/// <returns>
/// A sort operation that sorts in descending order.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="keySelector"/> is <c>null</c>.
/// </exception>
public static SortBy<TEntity, TValue> Descending<TValue>(
Expression<Func<TEntity, TValue>> keySelector)
{
Expand Down
55 changes: 55 additions & 0 deletions src/GreenDonut/src/GreenDonut.Data.Primitives/SortDefinition.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.Linq.Expressions;
using System.Text;

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

/// <summary>
/// Adds a sort operation to the definition.
/// </summary>
/// <param name="keySelector">
/// The field on which the sort operation is applied.
/// </param>
/// <typeparam name="TResult">
/// The type of the field on which the sort operation is applied.
/// </typeparam>
/// <returns>
/// The updated sort definition.
/// </returns>
public SortDefinition<T> AddAscending<TResult>(
Expression<Func<T, TResult>> keySelector)
{
if (keySelector == null)
{
throw new ArgumentNullException(nameof(keySelector));
}

var operations = Operations.Add(SortBy<T>.Ascending(keySelector));
return new SortDefinition<T>(operations);
}

/// <summary>
/// Adds a descending sort operation to the definition.
/// </summary>
/// <param name="keySelector">
/// The field on which the sort operation is applied.
/// </param>
/// <typeparam name="TResult">
/// The type of the field on which the sort operation is applied.
/// </typeparam>
/// <returns>
/// The updated sort definition.
/// </returns>
public SortDefinition<T> AddDescending<TResult>(
Expression<Func<T, TResult>> keySelector)
{
if (keySelector == null)
{
throw new ArgumentNullException(nameof(keySelector));
}

var operations = Operations.Add(SortBy<T>.Ascending(keySelector));
return new SortDefinition<T>(operations);
}

/// <summary>
/// Returns a string representation of the sort definition.
/// </summary>
/// <returns>
/// A string representation of the sort definition.
/// </returns>
public override string ToString()
{
if (Operations.Length == 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,19 @@ public static IDataLoader<TKey, Page<TValue>> WithPagingArguments<TKey, TValue>(
this IDataLoader<TKey, Page<TValue>> dataLoader,
PagingArguments pagingArguments)
where TKey : notnull
=> With(dataLoader, pagingArguments);
=> WithInternal(dataLoader, pagingArguments, null);

/// <summary>
/// Branches a DataLoader with the provided <see cref="PagingArguments"/>.
/// </summary>
/// <param name="dataLoader">
/// The DataLoader that shall be branched.
/// The DataLoader that shall be branched.
/// </param>
/// <param name="pagingArguments">
/// The paging arguments that shall exist as state in the branched DataLoader.
/// The paging arguments that shall exist as state in the branched DataLoader.
/// </param>
/// <param name="context">
/// The query context that shall exist as state in the branched DataLoader.
/// The query context that shall exist as state in the branched DataLoader.
/// </param>
/// <typeparam name="TKey">
/// The key type of the DataLoader.
Expand All @@ -64,11 +64,17 @@ public static IDataLoader<TKey, Page<TValue>> WithPagingArguments<TKey, TValue>(
/// <exception cref="ArgumentNullException">
/// Throws if the <paramref name="dataLoader"/> is <c>null</c>.
/// </exception>
public static IDataLoader<TKey, Page<TValue>> With<TKey, TValue>(
this IDataLoader<TKey, Page<TValue>> dataLoader,
public static IDataLoader<TKey, Page<TValue>> With<TKey, TValue>(this IDataLoader<TKey, Page<TValue>> dataLoader,
PagingArguments pagingArguments,
QueryContext<TValue>? context = null)
where TKey : notnull
=> WithInternal(dataLoader, pagingArguments, context);

private static IDataLoader<TKey, Page<TValue>> WithInternal<TKey, TValue>(
this IDataLoader<TKey, Page<TValue>> dataLoader,
PagingArguments pagingArguments,
QueryContext<TValue>? context)
where TKey : notnull
{
if (dataLoader is null)
{
Expand Down Expand Up @@ -160,7 +166,8 @@ public static IDataLoader<TKey, Page<TValue>> Select<TElement, TKey, TValue>(

var branchKey = selector.ComputeHash();
var state = new QueryState(DataLoaderStateKeys.Selector, new DefaultSelectorBuilder(selector));
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch, state);
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch,
state);
}

/// <summary>
Expand Down Expand Up @@ -200,11 +207,34 @@ public static IDataLoader<TKey, Page<TValue>> Where<TKey, TValue>(
}

var branchKey = predicate.ComputeHash();
var state = new QueryState(DataLoaderStateKeys.Predicate, GetOrCreateBuilder(dataLoader.ContextData, predicate));
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch, state);
var state = new QueryState(DataLoaderStateKeys.Predicate,
GetOrCreateBuilder(dataLoader.ContextData, predicate));
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch,
state);
}

public static IDataLoader<TKey, Page<TValue>> Order<TKey, TValue>(
/// <summary>
/// Adds a sorting definition as state to the DataLoader.
/// </summary>
/// <param name="dataLoader">
/// The DataLoader.
/// </param>
/// <param name="sortDefinition">
/// The sorting definition that shall be added as state to the DataLoader.
/// </param>
/// <typeparam name="TKey">
/// The key type of the DataLoader.
/// </typeparam>
/// <typeparam name="TValue">
/// The value type of the DataLoader.
/// </typeparam>
/// <returns>
/// Returns the DataLoader with the added projection.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Throws if the <paramref name="dataLoader"/> is <c>null</c>.
/// </exception>
public static IDataLoader<TKey, Page<TValue>> OrderBy<TKey, TValue>(
this IDataLoader<TKey, Page<TValue>> dataLoader,
SortDefinition<TValue>? sortDefinition)
where TKey : notnull
Expand All @@ -221,10 +251,11 @@ public static IDataLoader<TKey, Page<TValue>> Order<TKey, TValue>(

var branchKey = sortDefinition.ComputeHash();
var state = new QueryState(DataLoaderStateKeys.Sorting, sortDefinition);
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch, state);
return (IQueryDataLoader<TKey, Page<TValue>>)dataLoader.Branch(branchKey, DataLoaderStateHelper.CreateBranch,
state);
}

private static string ComputeHash<T>(this PagingArguments arguments, QueryContext<T>? context = null)
private static string ComputeHash<T>(this PagingArguments arguments, QueryContext<T>? context)
{
var hasher = ExpressionHasherPool.Shared.Get();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> queryable
/// <exception cref="ArgumentNullException">
/// Throws if <paramref name="queryable"/> is <c>null</c> or if <paramref name="queryContext"/> is <c>null</c>.
/// </exception>
public static IQueryable<T> Apply<T>(
public static IQueryable<T> With<T>(
this IQueryable<T> queryable,
QueryContext<T>? queryContext,
Func<SortDefinition<T>, SortDefinition<T>>? modifySortDefinition = null)
Expand Down
2 changes: 2 additions & 0 deletions src/GreenDonut/src/GreenDonut/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,6 @@ public static implicit operator TValue(Result<TValue> result)
=> result.Value;
}

#pragma warning disable RCS1194
public class KeyNotFoundException(string message) : Exception(message);
#pragma warning restore RCS1194
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,6 @@ public static IDataLoader<TKey, Page<TValue>> Order<TKey, TValue>(
where TKey : notnull
{
var definition = context.AsSortDefinition<TValue>();
return dataLoader.Order(definition);
return dataLoader.OrderBy(definition);
}
}
4 changes: 2 additions & 2 deletions src/HotChocolate/Data/test/Data.Tests/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,7 @@ public IQueryable<Author> GetAuthorsData(QueryContext<Author> context)
Books = new List<Book>()
},
}.AsQueryable()
.Apply(context);
.With(context);

[UseSorting]
public IQueryable<Author> GetAuthorsData2(QueryContext<Author> context)
Expand All @@ -1221,6 +1221,6 @@ public IQueryable<Author> GetAuthorsData2(QueryContext<Author> context)
Books = new List<Book>()
}
}.AsQueryable()
.Apply(context, t => t with { Operations = t.Operations.Add(SortBy<Author>.Ascending(t => t.Id)) });
.With(context, t => t with { Operations = t.Operations.Add(SortBy<Author>.Ascending(t => t.Id)) });
}
}

0 comments on commit 35c8091

Please sign in to comment.