src/Epam.GraphQL/Configuration/Implementations/Fields/ChildFields/ConnectionLoaderFieldBase.cs (90 lines of code) (raw):
// Copyright © 2020 EPAM Systems, Inc. All Rights Reserved. All information contained herein is, and remains the
// property of EPAM Systems, Inc. and/or its suppliers and is protected by international intellectual
// property law. Dissemination of this information or reproduction of this material is strictly forbidden,
// unless prior written permission is obtained from EPAM Systems, Inc
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Epam.GraphQL.Configuration.Implementations.FieldResolvers;
using Epam.GraphQL.Diagnostics;
using Epam.GraphQL.Extensions;
using Epam.GraphQL.Filters;
using Epam.GraphQL.Helpers;
using Epam.GraphQL.Loaders;
using Epam.GraphQL.Search;
namespace Epam.GraphQL.Configuration.Implementations.Fields.ChildFields
{
internal abstract class ConnectionLoaderFieldBase<TThis, TEntity, TChildLoader, TChildEntity, TExecutionContext> :
LoaderFieldBase<
TThis,
IConnectionField<TChildEntity, TExecutionContext>,
TEntity,
TChildLoader,
TChildEntity,
TExecutionContext>,
IConnectionField<TChildEntity, TExecutionContext>,
IConnectionField,
IVoid
where TChildLoader : Loader<TChildEntity, TExecutionContext>, new()
where TThis : ConnectionLoaderFieldBase<TThis, TEntity, TChildLoader, TChildEntity, TExecutionContext>
{
private static MethodInfo? _withFilterMethodInfo;
private static MethodInfo? _withSearchMethodInfo;
protected ConnectionLoaderFieldBase(
IChainConfigurationContext configurationContext,
BaseObjectGraphTypeConfigurator<TEntity, TExecutionContext> parent,
string name,
IQueryableResolver<TEntity, TChildEntity, TExecutionContext> resolver,
IGraphTypeDescriptor<TChildEntity, TExecutionContext> elementGraphType,
LazyQueryArguments? arguments,
ISearcher<TChildEntity, TExecutionContext>? searcher,
IEnumerable<(LambdaExpression SortExpression, SortDirection SortDirection)> naturalSorters)
: base(
configurationContext,
parent,
name,
resolver,
elementGraphType,
arguments,
searcher,
naturalSorters)
{
Initialize();
}
public IConnectionField WithFilter<TFilter>()
{
if (!ReflectionHelpers.TryFindMatchingGenericBaseType(typeof(TFilter), typeof(Filter<,,>), out var filterBaseType))
{
// TODO Make Dummy IConnectionField implementation
var configurationContext = ConfigurationContext.Chain<TFilter>(nameof(WithFilter));
var msg = configurationContext
.GetError($"Cannot find the corresponding generic base type `{typeof(Filter<,,>).HumanizedName()}` for type `{typeof(TFilter).HumanizedName()}`.", configurationContext);
throw new ConfigurationException(msg);
}
var filterArgument = filterBaseType.GetGenericArguments().Single(type => typeof(Input).IsAssignableFrom(type));
_withFilterMethodInfo ??= ReflectionHelpers.GetMethodInfo(
WithFilter<Filter<TChildEntity, Input, TExecutionContext>, Input>);
var withFilter = _withFilterMethodInfo.MakeGenericMethod(typeof(TFilter), filterArgument);
return withFilter.InvokeAndHoistBaseException<IConnectionField>(this);
}
IConnectionField IConnectionField.WithSearch<TSearcher>()
{
var baseType = ReflectionHelpers.FindMatchingGenericBaseType(typeof(TSearcher), typeof(ISearcher<,>));
_withSearchMethodInfo ??= ReflectionHelpers.GetMethodInfo(
WithSearch<ISearcher<TChildEntity, TExecutionContext>>);
var withSearcher = _withSearchMethodInfo.MakeGenericMethod(typeof(TSearcher));
return withSearcher.InvokeAndHoistBaseException<IConnectionField>(this);
}
private void Initialize()
{
Argument<string>(
"after",
"Only look at connected edges with cursors greater than the value of `after`.");
Argument<int?>(
"first",
"Specifies the number of edges to return starting from `after` or the first entry if `after` is not specified.");
Argument<string>(
"before",
"Only look at connected edges with cursors smaller than the value of `before`.");
Argument<int?>(
"last",
"Specifies the number of edges to return counting reversely from `before`, or the last entry if `before` is not specified.");
}
}
}