tgstation-server 6.19.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
QueryableExtensions.cs
Go to the documentation of this file.
1using System;
2using System.Linq;
3using System.Linq.Expressions;
4using System.Reflection;
5
6using GreenDonut.Data;
7
8using Microsoft.EntityFrameworkCore;
9
11
13{
18 {
29 QueryContext<TResult>? queryContext)
30 {
31 // taken verbatim from GreenDonut's With implementation
32 ArgumentNullException.ThrowIfNull(queryable);
33
34 if (queryContext == null)
35 return queryable;
36
37 var modified = false;
38 if (queryContext.Predicate != null)
39 {
40 queryable = queryable.Where(
41 TranslateLambda<TQueried, TResult, bool>(
42 queryContext.Predicate));
43 modified = true;
44 }
45
46 if (queryContext.Sorting?.Operations.Length > 0)
47 {
48 var definition = new SortDefinition<ProjectedPair<TQueried, TResult>>(
49 queryContext.Sorting.Operations
51
52 queryable = queryable.OrderBy(definition);
53 modified = true;
54 }
55
56 if (queryContext.Selector != null)
57 {
58 Expression<Func<ProjectedPair<TQueried, TResult>, TResult, ProjectedPair<TQueried, TResult>>> remapSelector =
59 (initialProjected, selectedResult) => new ProjectedPair<TQueried, TResult>
60 {
61 Queried = initialProjected.Queried,
62 Result = selectedResult,
63 };
64 Expression<Func<ProjectedPair<TQueried, TResult>, TResult>> resultSelector = projected => projected.Result;
65 var parameter = Expression.Parameter(typeof(ProjectedPair<TQueried, TResult>), "projectedParam");
66 var result = Expression.Parameter(typeof(TResult), "resultParam");
67 var initialResultExpr = Expression.Invoke(resultSelector, parameter);
68 var resultExpr = Expression.Invoke(queryContext.Selector, initialResultExpr);
69 var finalInvoke = Expression.Invoke(remapSelector, parameter, resultExpr);
70 var finalExpr = Expression.Lambda<Func<ProjectedPair<TQueried, TResult>, ProjectedPair<TQueried, TResult>>>(finalInvoke, parameter);
71
72 queryable = queryable.Select(finalExpr);
73 modified = true;
74 }
75
76 if (modified)
77 queryable = queryable
78 .TagWith("GraphQL Projections");
79
80 return queryable;
81 }
82
90 private static ISortBy<ProjectedPair<TQueried, TResult>> MapSortBy<TQueried, TResult>(ISortBy<TResult> sortBy)
91 {
92 var sortingKeyType = sortBy.GetType().GenericTypeArguments[1];
93
94 var factoryMethod = typeof(SortBy<ProjectedPair<TQueried, TResult>>)
95 .GetMethod(
96 sortBy.Ascending
97 ? nameof(SortBy<ProjectedPair<TQueried, TResult>>.Ascending)
98 : nameof(SortBy<ProjectedPair<TQueried, TResult>>.Descending))!;
99
100 var instantiatedLambdaTranslate = typeof(QueryableExtensions)
101 .GetMethod(nameof(TranslateLambda), BindingFlags.NonPublic | BindingFlags.Static)!
102 .MakeGenericMethod(typeof(TQueried), typeof(TResult), sortingKeyType);
103
104 var fixedLambda = instantiatedLambdaTranslate.Invoke(null, [sortBy.KeySelector])!;
105
106 var instantiatedFactoryMethod = factoryMethod.MakeGenericMethod(sortingKeyType);
107
108 return (ISortBy<ProjectedPair<TQueried, TResult>>)instantiatedFactoryMethod.Invoke(null, [fixedLambda])!;
109 }
110
119 private static Expression<Func<ProjectedPair<TQueried, TResult>, TDesired>> TranslateLambda<TQueried, TResult, TDesired>(LambdaExpression selectionExpression)
120 {
121 Expression<Func<ProjectedPair<TQueried, TResult>, TResult>> resultSelector = projected => projected.Result;
122
123 var parameter = Expression.Parameter(typeof(ProjectedPair<TQueried, TResult>), "projectedTranslateParam");
124 var result = Expression.Invoke(resultSelector, parameter);
125 var expr = Expression.Invoke(selectionExpression, result);
126
127 return Expression.Lambda<Func<ProjectedPair<TQueried, TResult>, TDesired>>(expr, parameter);
128 }
129 }
130}
DTO for moving database projected objects through the system.
required TQueried Queried
The originally queried TQueried .
static Expression< Func< ProjectedPair< TQueried, TResult >, TDesired > > TranslateLambda< TQueried, TResult, TDesired >(LambdaExpression selectionExpression)
Translate a given selectionExpression on a TResult onto its ProjectedPair<TQueried,...
static ISortBy< ProjectedPair< TQueried, TResult > > MapSortBy< TQueried, TResult >(ISortBy< TResult > sortBy)
Map a given sortBy onto a ProjectedPair<TQueried, TResult>.
static IQueryable< ProjectedPair< TQueried, TResult > > With< TQueried, TResult >(this IQueryable< ProjectedPair< TQueried, TResult > > queryable, QueryContext< TResult >? queryContext)
Map a given queryContext to project onto a given queryable .