private static ApplyProjection CreateApplicatorAsync <TEntityType>() { return((context, input) => { if (input is null) { return input; } // if projections are already applied we can skip var skipProjection = context.LocalContextData.TryGetValue(SkipProjectionKey, out object?skip) && skip is true; // ensure sorting is only applied once context.LocalContextData = context.LocalContextData.SetItem(SkipProjectionKey, true); if (skipProjection) { return input; } var visitorContext = new QueryableProjectionContext( context, context.ObjectType, context.Field.Type.UnwrapRuntimeType()); var visitor = new QueryableProjectionVisitor(); visitor.Visit(visitorContext); Expression <Func <TEntityType, TEntityType> > projection = visitorContext.Project <TEntityType>(); input = input switch { IQueryable <TEntityType> q => q.Select(projection), IEnumerable <TEntityType> e => e.AsQueryable().Select(projection), QueryableExecutable <TEntityType> ex => ex.WithSource(ex.Source.Select(projection)), _ => input }; return input; }); }
public override FieldMiddleware CreateExecutor <TEntityType>() { 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); if (context.Result is not null) { var visitorContext = new QueryableProjectionContext( context, context.ObjectType, context.Field.Type.UnwrapRuntimeType()); var visitor = new QueryableProjectionVisitor(); visitor.Visit(visitorContext); Expression <Func <TEntityType, TEntityType> > projection = visitorContext.Project <TEntityType>(); context.Result = context.Result switch { IQueryable <TEntityType> q => q.Select(projection), IEnumerable <TEntityType> e => e.AsQueryable().Select(projection), QueryableExecutable <TEntityType> ex => ex.WithSource(ex.Source.Select(projection)), _ => context.Result }; } } } }
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 filter argument. If the filter argument is already on the context // we use this. This enabled overriding the context with LocalContextData IInputField argument = context.Field.Arguments[argumentName]; IValueNode filter = context.LocalContextData.ContainsKey(ContextValueNodeKey) && context.LocalContextData[ContextValueNodeKey] is IValueNode node ? node : context.ArgumentLiteral <IValueNode>(argumentName); // if no filter is defined we can stop here and yield back control. if (filter.IsNull() || (context.LocalContextData.TryGetValue( SkipFilteringKey, out object?skipObject) && skipObject is bool skip && skip)) { return; } if (argument.Type is IFilterInputType filterInput && context.Field.ContextData.TryGetValue( ContextVisitFilterArgumentKey, out object?executorObj) && executorObj is VisitFilterArgument executor) { var inMemory = context.Result is QueryableExecutable <TEntityType> executable && executable.InMemory || context.Result is not IQueryable || context.Result is EnumerableQuery; QueryableFilterContext visitorContext = executor( filter, filterInput, inMemory); // compile expression tree if (visitorContext.TryCreateLambda( out Expression <Func <TEntityType, bool> >?where)) { context.Result = context.Result switch { IQueryable <TEntityType> q => q.Where(where), IEnumerable <TEntityType> e => e.AsQueryable().Where(where), QueryableExecutable <TEntityType> ex => ex.WithSource(ex.Source.Where(where)), _ => context.Result }; } else { if (visitorContext.Errors.Count > 0) { context.Result = Array.Empty <TEntityType>(); foreach (IError error in visitorContext.Errors) { context.ReportError(error.WithPath(context.Path)); } } } } } }
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() || (context.LocalContextData.TryGetValue( SkipSortingKey, out object?skipObject) && skipObject is bool skip && skip)) { return; } if (argument.Type is ListType lt && lt.ElementType is NonNullType nn && nn.NamedType() is ISortInputType sortInput && context.Field.ContextData.TryGetValue( ContextVisitSortArgumentKey, out object?executorObj) && executorObj is VisitSortArgument executor) { var inMemory = context.Result is QueryableExecutable <TEntityType> executable && executable.InMemory || context.Result is not IQueryable || context.Result is EnumerableQuery; QueryableSortContext visitorContext = executor( sort, sortInput, inMemory); // 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 = context.Result switch { IQueryable <TEntityType> q => visitorContext.Sort(q), IEnumerable <TEntityType> e => visitorContext.Sort(e.AsQueryable()), QueryableExecutable <TEntityType> ex => ex.WithSource(visitorContext.Sort(ex.Source)), _ => context.Result }; } } } }