-
-
Notifications
You must be signed in to change notification settings - Fork 722
/
QueryableSortProvider.cs
87 lines (75 loc) · 2.91 KB
/
QueryableSortProvider.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using HotChocolate.Language;
using HotChocolate.Resolvers;
using HotChocolate.Types;
namespace HotChocolate.Data.Sorting.Expressions
{
public class QueryableSortProvider
: SortProvider<QueryableSortContext>
{
public QueryableSortProvider()
{
}
public QueryableSortProvider(
Action<ISortProviderDescriptor<QueryableSortContext>> configure)
: base(configure)
{
}
protected virtual SortVisitor<QueryableSortContext, QueryableSortOperation> Visitor { get; }
= new SortVisitor<QueryableSortContext, QueryableSortOperation>();
public override FieldMiddleware CreateExecutor<TEntityType>(NameString argumentName)
{
return next => context => ExecuteAsync(next, context);
async ValueTask ExecuteAsync(
FieldDelegate next,
IMiddlewareContext context)
{
// first we let the pipeline run and produce a result.
await next(context).ConfigureAwait(false);
// next we get the sort argument.
IInputField argument = context.Field.Arguments[argumentName];
IValueNode sort = context.ArgumentLiteral<IValueNode>(argumentName);
// if no sort is defined we can stop here and yield back control.
if (sort.IsNull())
{
return;
}
IQueryable<TEntityType>? source = null;
if (context.Result is IQueryable<TEntityType> q)
{
source = q;
}
else if (context.Result is IEnumerable<TEntityType> e)
{
source = e.AsQueryable();
}
if (source != null &&
argument.Type is ListType lt &&
lt.ElementType is ISortInputType sortInput)
{
var visitorContext = new QueryableSortContext(
sortInput,
source is EnumerableQuery);
// rewrite GraphQL input object into expression tree.
Visitor.Visit(sort, visitorContext);
// compile expression tree
if (visitorContext.Errors.Count > 0)
{
context.Result = Array.Empty<TEntityType>();
foreach (IError error in visitorContext.Errors)
{
context.ReportError(error.WithPath(context.Path));
}
}
else
{
context.Result = visitorContext.Sort(source);
}
}
}
}
}
}