Skip to content

Commit

Permalink
Fixed issue with extracting predicates from IFilterContext. (#7693)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Nov 6, 2024
1 parent f658ce0 commit 013a451
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void Handled(bool isHandled)
return null;
}

private object? Serialize(IFilterValueNode? value)
private static object? Serialize(IFilterValueNode? value)
{
switch (value)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ context.LocalContextData[ContextValueNodeKey] is IValueNode node
return null;
}

FilterContext filterContext =
new(context, filterInput, filter, context.Service<InputParser>());
var filterContext = new FilterContext(context, filterInput, filter, context.Service<InputParser>());

// disable the execution of filtering by default
filterContext.Handled(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,18 @@ private ApplyFiltering CreateApplicator<TEntityType>(string argumentName)
=> (context, input) =>
{
var inMemory = IsInMemoryQuery<TEntityType>(input);

// if no filter is defined we can stop here and yield back control.
var skipFiltering = context.GetLocalStateOrDefault<bool>(SkipFilteringKey);

// ensure filtering is only applied once
context.SetLocalState(SkipFilteringKey, true);

if (skipFiltering)
{
return input;
}

var predicate = AsPredicate<TEntityType>(context, argumentName, inMemory);

if (predicate is not null)
Expand All @@ -205,13 +217,7 @@ private ApplyFiltering CreateApplicator<TEntityType>(string argumentName)
var filter = context.GetLocalStateOrDefault<IValueNode>(ContextValueNodeKey) ??
context.ArgumentLiteral<IValueNode>(argumentName);

// if no filter is defined we can stop here and yield back control.
var skipFiltering = context.GetLocalStateOrDefault<bool>(SkipFilteringKey);

// ensure filtering is only applied once
context.SetLocalState(SkipFilteringKey, true);

if (filter.IsNull() || skipFiltering)
if (filter.IsNull())
{
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using HotChocolate.Data.Filters;
using HotChocolate.Execution.Processing;

// ReSharper disable once CheckNamespace
namespace System.Linq;

/// <summary>
/// Provides extension methods to integrate <see cref="IQueryable{T}"/>
/// with <see cref="ISelection"/> and <see cref="IFilterContext"/>.
/// </summary>
public static class QueryableExtensions
{
/// <summary>
/// Applies a selection to the queryable.
/// </summary>
/// <param name="queryable">
/// The queryable that shall be projected.
/// </param>
/// <param name="selection">
/// The selection that shall be applied to the queryable.
/// </param>
/// <typeparam name="T">
/// The type of the queryable.
/// </typeparam>
/// <returns>
/// Returns a queryable that has the selection applied.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Throws if <paramref name="queryable"/> is <c>null</c> or if <paramref name="selection"/> is <c>null</c>.
/// </exception>
public static IQueryable<T> Select<T>(this IQueryable<T> queryable, ISelection selection)
{
if (queryable is null)
{
throw new ArgumentNullException(nameof(queryable));
}

if (selection is null)
{
throw new ArgumentNullException(nameof(selection));
}

return queryable.Select(selection.AsSelector<T>());
}

/// <summary>
/// Applies a filter context to the queryable.
/// </summary>
/// <param name="queryable">
/// The queryable that shall be filtered.
/// </param>
/// <param name="filter">
/// The filter context that shall be applied to the queryable.
/// </param>
/// <typeparam name="T">
/// The type of the queryable.
/// </typeparam>
/// <returns>
/// Returns a queryable that has the filter applied.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Throws if <paramref name="queryable"/> is <c>null</c> or if <paramref name="filter"/> is <c>null</c>.
/// </exception>
public static IQueryable<T> Where<T>(this IQueryable<T> queryable, IFilterContext filter)
{
if (queryable is null)
{
throw new ArgumentNullException(nameof(queryable));
}

if (filter is null)
{
throw new ArgumentNullException(nameof(filter));
}

var predicate = filter.AsPredicate<T>();
return predicate is null ? queryable : queryable.Where(predicate);
}
}
2 changes: 1 addition & 1 deletion src/HotChocolate/Data/src/Data/HotChocolate.Data.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<AssemblyName>HotChocolate.Data</AssemblyName>
<RootNamespace>HotChocolate.Data</RootNamespace>
<Description>Contains ready to use extensions for data management in HotChocolate. This includes filtering, projections and sorting</Description>
<NoWarn>HC8001;$(NoWarn)</NoWarn>
<NoWarn>HC8001;GD0001;$(NoWarn)</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit 013a451

Please sign in to comment.