Example #1
0
        FieldType BuildQueryField <TSource, TReturn>(
            string name,
            Func <ResolveFieldContext <TSource>, IQueryable <TReturn> > resolve,
            IEnumerable <QueryArgument> arguments,
            Type graphType)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);
            graphType = GraphTypeFinder.FindGraphType <TReturn>(graphType);
            var listGraphType = MakeListGraphType(graphType);

            return(new FieldType
            {
                Name = name,
                Type = listGraphType,
                Arguments = ArgumentAppender.GetQueryArguments(arguments),
                Resolver = new AsyncFieldResolver <TSource, IEnumerable <TReturn> >(
                    async context =>
                {
                    var returnTypes = resolve(context);
                    var withIncludes = includeAppender.AddIncludes(returnTypes, context);
                    var withArguments = withIncludes.ApplyGraphQlArguments(context);
                    var list = await withArguments.ToListAsync(context.CancellationToken);
                    return await filters.ApplyFilter(list, context.UserContext);
                })
            });
        }
Example #2
0
        ConnectionBuilder <FakeGraph, TSource> BuildListConnectionField <TSource, TReturn>(
            string name,
            Func <ResolveFieldContext <TSource>, IEnumerable <TReturn> > resolve,
            IEnumerable <string> includeName,
            int pageSize,
            Type graphType)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);
            Guard.AgainstNegative(nameof(pageSize), pageSize);
            graphType = GraphTypeFinder.FindGraphType <TReturn>(graphType);
            var fieldType = GetFieldType <TSource>(name, graphType);
            var builder   = ConnectionBuilder <FakeGraph, TSource> .Create(name);

            builder.PageSize(pageSize);
            SetField(builder, fieldType);
            IncludeAppender.SetIncludeMetadata(builder.FieldType, name, includeName);
            builder.ResolveAsync(async context =>
            {
                var enumerable = resolve(context);
                enumerable     = enumerable.ApplyGraphQlArguments(context);
                enumerable     = await filters.ApplyFilter(enumerable, context.UserContext);
                var page       = enumerable.ToList();

                return(ConnectionConverter.ApplyConnectionContext(
                           page,
                           context.First,
                           context.After,
                           context.Last,
                           context.Before));
            });
            return(builder);
        }
        public void AddNavigationConnectionField <TSource, TReturn>(
            ComplexGraphType <TSource> graph,
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IEnumerable <TReturn> >?resolve = null,
            Type?itemGraphType = null,
            IEnumerable <QueryArgument>?arguments = null,
            IEnumerable <string>?includeNames     = null,
            int pageSize       = 10,
            string?description = null)
            where TReturn : class
        {
            Guard.AgainstNull(nameof(graph), graph);

            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNegative(nameof(pageSize), pageSize);

            itemGraphType ??= GraphTypeFinder.FindGraphType <TReturn>();
            var fieldType = GetFieldType <TSource>(name, itemGraphType);

            var builder = ConnectionBuilder <TSource> .Create <FakeGraph>(name);

            SetField(builder, fieldType);
            if (description != null)
            {
                builder.Description(description);
            }

            builder.PageSize(pageSize).Bidirectional();
            IncludeAppender.SetIncludeMetadata(builder.FieldType, name, includeNames);

            var hasId = keyNames.ContainsKey(typeof(TReturn));

            if (resolve != null)
            {
                builder.ResolveAsync(async context =>
                {
                    var efFieldContext = BuildContext(context);

                    var enumerable = resolve(efFieldContext);

                    enumerable = enumerable.ApplyGraphQlArguments(hasId, context);
                    enumerable = await efFieldContext.Filters.ApplyFilter(enumerable, context.UserContext);
                    var page   = enumerable.ToList();

                    return(ConnectionConverter.ApplyConnectionContext(
                               page,
                               context.First,
                               context.After,
                               context.Last,
                               context.Before));
                });
            }

            var connection = builder;

            var field = graph.AddField(connection.FieldType);

            field.AddWhereArgument(hasId, arguments);
        }
        FieldType BuildSingleField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, Task <IQueryable <TReturn> > > resolve,
            IEnumerable <QueryArgument>?arguments,
            Type?graphType,
            bool nullable)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);

            //lookup the graph type if not explicitly specified
            graphType ??= GraphTypeFinder.FindGraphType <TReturn>();
            //if not nullable, construct a non-null graph type for the specified graph type
            var wrappedType = nullable ? graphType : typeof(NonNullGraphType <>).MakeGenericType(graphType);

            //build the field
            return(new FieldType
            {
                Name = name,
                Type = wrappedType,
                //append the default query arguments to the specified argument list
                Arguments = ArgumentAppender.GetQueryArguments(arguments),
                //custom resolve function
                Resolver = new AsyncFieldResolver <TSource, TReturn?>(
                    async context =>
                {
                    var efFieldContext = BuildContext(context);
                    //get field names of the table's primary key(s)
                    var names = GetKeyNames <TReturn>();
                    //run the specified resolve function
                    var returnTypes = await resolve(efFieldContext);
                    //include sub tables in the query based on the metadata stored for the requested graph
                    var withIncludes = includeAppender.AddIncludes(returnTypes, context);
                    //apply any query filters specified in the arguments
                    var withArguments = withIncludes.ApplyGraphQlArguments(context, names);
                    //run the query
                    var single = await withArguments.SingleOrDefaultAsync(context.CancellationToken);
                    //apply global filters to the returned value
                    if (single != null)
                    {
                        if (await efFieldContext.Filters.ShouldInclude(context.UserContext, single))
                        {
                            return single;
                        }
                    }

                    //if no value was found, or if the returned value was filtered out by the global filters,
                    //  either return null, or throw an error if the field is not nullable
                    if (nullable)
                    {
                        return null;
                    }

                    throw new ExecutionError("Not found");
                })
            });
        }
Example #5
0
        static Type MakeListGraphType <TReturn>(Type?itemGraphType)
            where TReturn : class
        {
            if (itemGraphType == null)
            {
                itemGraphType = GraphTypeFinder.FindGraphType <TReturn>();
            }

            return(nonNullType.MakeGenericType(listGraphType.MakeGenericType(itemGraphType)));
        }
Example #6
0
        FieldType BuildNavigationField <TSource, TReturn>(
            Type graphType,
            string name,
            Func <ResolveFieldContext <TSource>, IEnumerable <TReturn> > resolve,
            IEnumerable <string> includeNames,
            IEnumerable <QueryArgument> arguments)
            where TReturn : class
        {
            graphType = GraphTypeFinder.FindGraphType <TReturn>(graphType);
            var listGraphType = MakeListGraphType(graphType);

            return(BuildNavigationField(name, resolve, includeNames, listGraphType, arguments));
        }
        ConnectionBuilder <TSource> BuildQueryConnectionField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IQueryable <TReturn> >?resolve,
            int pageSize,
            Type?itemGraphType,
            string?description)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNegative(nameof(pageSize), pageSize);

            itemGraphType ??= GraphTypeFinder.FindGraphType <TReturn>();
            var fieldType = GetFieldType <TSource>(name, itemGraphType);

            var builder = ConnectionBuilder <TSource> .Create <FakeGraph>(name);

            SetField(builder, fieldType);
            if (description != null)
            {
                builder.Description(description);
            }
            builder.PageSize(pageSize).Bidirectional();

            if (resolve != null)
            {
                builder.Resolve(
                    context =>
                {
                    var efFieldContext = BuildContext(context);
                    var query          = resolve(efFieldContext);
                    if (disableTracking)
                    {
                        query = query.AsNoTracking();
                    }
                    query     = includeAppender.AddIncludes(query, context);
                    var names = GetKeyNames <TReturn>();
                    query     = query.ApplyGraphQlArguments(context, names, true);
                    return(query
                           .ApplyConnectionContext(
                               context.First,
                               context.After,
                               context.Last,
                               context.Before,
                               context,
                               context.CancellationToken,
                               efFieldContext.Filters));
                });
            }

            return(builder);
        }
Example #8
0
        ConnectionBuilder <FakeGraph, TSource> BuildQueryConnectionField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IQueryable <TReturn> > resolve,
            int pageSize,
            Type?graphType)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);
            Guard.AgainstNegative(nameof(pageSize), pageSize);

            //lookup the graph type if not explicitly specified
            graphType ??= GraphTypeFinder.FindGraphType <TReturn>();
            //create a ConnectionBuilder<graphType, TSource> type by invoking the static Create method on the generic type
            var fieldType = GetFieldType <TSource>(name, graphType);
            //create a ConnectionBuilder<FakeGraph, TSource> which will be returned from this method
            var builder = ConnectionBuilder <FakeGraph, TSource> .Create(name);

            //set the page size
            builder.PageSize(pageSize);
            //using reflection, override the private field type property of the ConnectionBuilder<FakeGraph, TSource> to be the ConnectionBuilder<graphType, TSource> object
            SetField(builder, fieldType);

            //set the resolve function (note: this is not async capable)
            builder.Resolve(
                context =>
            {
                //obtain the ef context
                var efFieldContext = BuildContext(context);
                //run the resolve function, then include the related tables on the returned query
                var withIncludes = includeAppender.AddIncludes(resolve(efFieldContext), context);
                //get field names of the table's primary key(s)
                var names = GetKeyNames <TReturn>();
                //apply any query filters specified in the arguments
                var withArguments = withIncludes.ApplyGraphQlArguments(context, names);
                //apply skip/take to query as appropriate, and return the query
                return(withArguments
                       .ApplyConnectionContext(
                           context.First,
                           context.After,
                           context.Last,
                           context.Before,
                           context,
                           context.CancellationToken,
                           efFieldContext.Filters));
                //note: does not apply global filters
            });

            //return the field to be added to the graph
            return(builder);
        }
        ConnectionBuilder <FakeGraph, TSource> BuildListConnectionField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IEnumerable <TReturn> > resolve,
            IEnumerable <string> includeName,
            int pageSize,
            Type graphType)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);
            Guard.AgainstNegative(nameof(pageSize), pageSize);

            //lookup the graph type if not explicitly specified
            graphType = graphType ?? GraphTypeFinder.FindGraphType <TReturn>();
            //create a ConnectionBuilder<graphType, TSource> type by invoking the static Create method on the generic type
            var fieldType = GetFieldType <TSource>(name, graphType);
            //create a ConnectionBuilder<FakeGraph, TSource> which will be returned from this method
            var builder = ConnectionBuilder <FakeGraph, TSource> .Create(name);

            //set the page size
            builder.PageSize(pageSize);
            //using reflection, override the private field type property of the ConnectionBuilder<FakeGraph, TSource> to be the ConnectionBuilder<graphType, TSource> object
            SetField(builder, fieldType);
            //add the metadata for the tables to be included in the query to the ConnectionBuilder<graphType, TSource> object
            IncludeAppender.SetIncludeMetadata(builder.FieldType, name, includeName);
            //set the custom resolver
            builder.ResolveAsync(async context =>
            {
                var efFieldContext = BuildContext(context);
                //run the specified resolve function
                var enumerable = resolve(efFieldContext);
                //apply any query filters specified in the arguments
                enumerable = enumerable.ApplyGraphQlArguments(context);
                //apply the global filter on each individually enumerated item
                enumerable = await efFieldContext.Filters.ApplyFilter(enumerable, context.UserContext);
                //pagination does NOT occur server-side at this point, as the query has already executed
                var page = enumerable.ToList();
                //return the proper page of data
                return(ConnectionConverter.ApplyConnectionContext(
                           page,
                           context.First,
                           context.After,
                           context.Last,
                           context.Before));
            });

            //return the field to be added to the graph
            return(builder);
        }
        public void AddQueryConnectionField <TSource, TReturn>(
            IComplexGraphType graph,
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IQueryable <TReturn> >?resolve = null,
            Type?itemGraphType = null,
            IEnumerable <QueryArgument>?arguments = null,
            int pageSize       = 10,
            string?description = null)
            where TReturn : class
        {
            itemGraphType ??= GraphTypeFinder.FindGraphType <TReturn>();
            var addConnectionT = addQueryableConnection.MakeGenericMethod(typeof(TSource), itemGraphType, typeof(TReturn));

            addConnectionT.Invoke(this, new object?[] { graph, name, resolve, arguments, pageSize, description });
        }
        ConnectionBuilder <TSource> BuildListConnectionField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IEnumerable <TReturn> >?resolve,
            IEnumerable <string>?includeName,
            int pageSize,
            Type?itemGraphType,
            string?description)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNegative(nameof(pageSize), pageSize);

            itemGraphType ??= GraphTypeFinder.FindGraphType <TReturn>();
            var fieldType = GetFieldType <TSource>(name, itemGraphType);

            var builder = ConnectionBuilder <TSource> .Create <FakeGraph>(name);

            if (description != null)
            {
                builder.Description(description);
            }
            builder.PageSize(pageSize);
            SetField(builder, fieldType);
            IncludeAppender.SetIncludeMetadata(builder.FieldType, name, includeName);

            if (resolve != null)
            {
                builder.ResolveAsync(async context =>
                {
                    var efFieldContext = BuildContext(context);

                    var enumerable = resolve(efFieldContext);

                    enumerable = enumerable.ApplyGraphQlArguments(context);
                    enumerable = await efFieldContext.Filters.ApplyFilter(enumerable, context.UserContext);
                    var page   = enumerable.ToList();

                    return(ConnectionConverter.ApplyConnectionContext(
                               page,
                               context.First,
                               context.After,
                               context.Last,
                               context.Before));
                });
            }

            return(builder);
        }
        PaginationBuilder <TSource> BuildQueryPaginationField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IQueryable <TReturn> >?resolve,
            int page,
            int row,
            Type?itemGraphType,
            string?description)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNegative(nameof(page), page);
            Guard.AgainstNegative(nameof(row), row);

            itemGraphType ??= GraphTypeFinder.FindGraphType <TReturn>();
            var fieldType = GetPaginationFieldType <TSource>(name, itemGraphType);

            var builder = PaginationBuilder <TSource> .Create <FakeGraph>(name);

            if (description != null)
            {
                builder.Description(description);
            }
            builder.Page(page).Row(row);
            SetField(builder, fieldType);

            if (resolve != null)
            {
                builder.Resolve(
                    context =>
                {
                    var efFieldContext = BuildContext(context);
                    var query          = resolve(efFieldContext);
                    query     = includeAppender.AddIncludes(query, context);
                    var names = GetKeyNames <TReturn>();
                    query     = query.ApplyGraphQlArguments(context, names);
                    return(query
                           .ApplyPaginationContext(
                               context.Page,
                               context.Row,
                               context,
                               context.CancellationToken,
                               efFieldContext.Filters));
                });
            }

            return(builder);
        }
        FieldType BuildQueryFieldAsync <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, Task <IQueryable <TReturn> > > resolve,
            IEnumerable <QueryArgument> arguments,
            Type graphType)
            where TReturn : class
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (resolve == null)
            {
                throw new ArgumentNullException(nameof(resolve));
            }
            //lookup the graph type if not explicitly specified
            graphType = graphType ?? GraphTypeFinder.FindGraphType <TReturn>();
            //create a list graph type based on the base field graph type
            var listGraphType = MakeListGraphType(graphType);

            //build the field
            return(new FieldType
            {
                Name = name,
                Type = listGraphType,
                //append the default query arguments to the specified argument list
                Arguments = ArgumentAppender.GetQueryArguments(arguments),
                //custom resolve function
                Resolver = new AsyncFieldResolver <TSource, IEnumerable <TReturn> >(
                    async context =>
                {
                    //get field names of the table's primary key(s)
                    var names = GetKeyNames <TReturn>();
                    //run the specified resolve function
                    var returnTypes = await resolve(BuildEfContextFromGraphQlContext(context));
                    //include subtables in the query based on the metadata stored for the requested graph
                    var withIncludes = includeAppender.AddIncludes(returnTypes, context);
                    //apply any query filters specified in the arguments
                    var withArguments = withIncludes.ApplyGraphQlArguments(context, names);
                    //query the database
                    var list = await withArguments.ToListAsync(context.CancellationToken);
                    //apply the global filter on each individually enumerated item
                    return filters == null ? list : await filters.ApplyFilter(list, context.UserContext);
                })
            });
        }
Example #14
0
        FieldType BuildNavigationField <TSource, TReturn>(
            Type graphType,
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IEnumerable <TReturn> > resolve,
            IEnumerable <string> includeNames,
            IEnumerable <QueryArgument> arguments)
            where TReturn : class
        {
            //lookup the graph type if not explicitly specified
            graphType = graphType ?? GraphTypeFinder.FindGraphType <TReturn>();
            //graphType represents the base field type, not the list graph type
            //create a list graph type based on the graph type specified
            var listGraphType = MakeListGraphType(graphType);

            //build the navigation field
            return(BuildNavigationField(name, resolve, includeNames, listGraphType, arguments));
        }
Example #15
0
        public FieldType AddNavigationField <TSource, TReturn>(
            ComplexGraphType <TSource> graph,
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, TReturn?>?resolve = null,
            Type?graphType = null,
            IEnumerable <string>?includeNames = null,
            string?description = null)
            where TReturn : class
        {
            Guard.AgainstNull(nameof(graph), graph);
            Guard.AgainstNullWhiteSpace(nameof(name), name);

            graphType ??= GraphTypeFinder.FindGraphType <TReturn>();

            FieldType field = new()
            {
                Name        = name,
                Type        = graphType,
                Description = description
            };

            IncludeAppender.SetIncludeMetadata(field, name, includeNames);

            if (resolve != null)
            {
                field.Resolver = new AsyncFieldResolver <TSource, TReturn?>(
                    async context =>
                {
                    var fieldContext = BuildContext(context);

                    var result = resolve(fieldContext);
                    if (await fieldContext.Filters.ShouldInclude(context.UserContext, result))
                    {
                        return(result);
                    }

                    return(null);
                });
            }

            return(graph.AddField(field));
        }
    }
    public void AddNavigationConnectionField <TSource, TReturn>(
        ComplexGraphType <TSource> graph,
        string name,
        Func <ResolveEfFieldContext <TDbContext, TSource>, IEnumerable <TReturn> >?resolve = null,
        Type?itemGraphType = null,
        IEnumerable <QueryArgument>?arguments = null,
        IEnumerable <string>?includeNames     = null,
        int pageSize       = 10,
        string?description = null)
        where TReturn : class
    {
        Guard.AgainstWhiteSpace(nameof(name), name);
        Guard.AgainstNegative(nameof(pageSize), pageSize);

        itemGraphType ??= GraphTypeFinder.FindGraphType <TReturn>();

        var addConnectionT = addEnumerableConnection.MakeGenericMethod(typeof(TSource), itemGraphType, typeof(TReturn));

        addConnectionT.Invoke(this, new object?[] { graph, name, resolve, pageSize, description, arguments, includeNames });
    }
Example #17
0
        FieldType BuildQueryField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, Task <IQueryable <TReturn> > > resolve,
            IEnumerable <QueryArgument>?arguments,
            Type?graphType)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);
            //lookup the graph type if not explicitly specified
            graphType ??= GraphTypeFinder.FindGraphType <TReturn>();
            //create a list graph type based on the base field graph type
            var listGraphType = MakeListGraphType(graphType);

            //build the field
            return(new FieldType
            {
                Name = name,
                Type = listGraphType,
                //append the default query arguments to the specified argument list
                Arguments = ArgumentAppender.GetQueryArguments(arguments),
                //custom resolve function
                Resolver = new AsyncFieldResolver <TSource, IEnumerable <TReturn> >(
                    async context =>
                {
                    var efFieldContext = BuildContext(context);
                    //get field names of the table's primary key(s)
                    var names = GetKeyNames <TReturn>();
                    //run the specified resolve function
                    var query = await resolve(efFieldContext);
                    //include sub tables in the query based on the metadata stored for the requested graph
                    query = includeAppender.AddIncludes(query, context);
                    //apply any query filters specified in the arguments
                    query = query.ApplyGraphQlArguments(context, names);
                    //query the database
                    var list = await query.ToListAsync(context.CancellationToken);
                    //apply the global filter on each individually enumerated item
                    return await efFieldContext.Filters.ApplyFilter(list, context.UserContext);
                })
            });
        }
        FieldType BuildNavigationField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, TReturn> resolve,
            IEnumerable <string> includeNames,
            Type graphType)
            where TReturn : class
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (resolve == null)
            {
                throw new ArgumentNullException(nameof(resolve));
            }

            //lookup the graph type if not explicitly specified
            graphType = graphType ?? GraphTypeFinder.FindGraphType <TReturn>();
            //build field
            return(new FieldType
            {
                Name = name,
                Type = graphType,
                //add the metadata for the tables to be included in the query
                Metadata = IncludeAppender.GetIncludeMetadata(name, includeNames),
                //custom resolve function simply applies the global filters; typically it's a pass-through
                Resolver = new AsyncFieldResolver <TSource, TReturn>(async context =>
                {
                    //run resolve function
                    var result = resolve(BuildEfContextFromGraphQlContext(context));
                    //apply global filters and return null if necessary
                    if (filters == null || await filters.ShouldInclude(context.UserContext, result))
                    {
                        return result;
                    }

                    return null;
                })
            });
        }
        FieldType BuildSingleField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, Task <IQueryable <TReturn> > > resolve,
            IEnumerable <QueryArgument> arguments,
            Type graphType)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);

            graphType = GraphTypeFinder.FindGraphType <TReturn>(graphType);
            var notNullGraph = typeof(NonNullGraphType <>);
            var wrappedType  = notNullGraph.MakeGenericType(graphType);

            return(new FieldType
            {
                Name = name,
                Type = wrappedType,
                Arguments = ArgumentAppender.GetQueryArguments(arguments),
                Resolver = new AsyncFieldResolver <TSource, TReturn>(
                    async context =>
                {
                    var returnTypes = await resolve(BuildEfContextFromGraphQlContext(context));
                    var withIncludes = includeAppender.AddIncludes(returnTypes, context);
                    var names = GetKeyNames <TReturn>();
                    var withArguments = withIncludes.ApplyGraphQlArguments(context, names);

                    var single = await withArguments.SingleOrDefaultAsync(context.CancellationToken);
                    if (single != null)
                    {
                        if (await filters.ShouldInclude(context.UserContext, single))
                        {
                            return single;
                        }
                    }

                    throw new ExecutionError("Not found");
                })
            });
        }
Example #20
0
        FieldType BuildNavigationField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, TReturn?>?resolve,
            IEnumerable <string>?includeNames,
            Type?graphType,
            string?description)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);

            graphType ??= GraphTypeFinder.FindGraphType <TReturn>();

            var fieldType = new FieldType
            {
                Name        = name,
                Type        = graphType,
                Metadata    = IncludeAppender.GetIncludeMetadata(name, includeNames),
                Description = description
            };

            if (resolve != null)
            {
                fieldType.Resolver = new AsyncFieldResolver <TSource, TReturn?>(
                    async context =>
                {
                    var efFieldContext = BuildContext(context);

                    var result = resolve(efFieldContext);
                    if (await efFieldContext.Filters.ShouldInclude(context.UserContext, result))
                    {
                        return(result);
                    }

                    return(null);
                });
            }

            return(fieldType);
        }
        ConnectionBuilder <FakeGraph, TSource> BuildQueryConnectionField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IQueryable <TReturn> > resolve,
            int pageSize,
            Type graphType)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);
            Guard.AgainstNegative(nameof(pageSize), pageSize);

            graphType = GraphTypeFinder.FindGraphType <TReturn>(graphType);
            var fieldType = GetFieldType <TSource>(name, graphType);
            var builder   = ConnectionBuilder <FakeGraph, TSource> .Create(name);

            builder.PageSize(pageSize);
            SetField(builder, fieldType);

            builder.Resolve(
                context =>
            {
                var efFieldContext = BuildEfContextFromGraphQlContext(context);
                var withIncludes   = includeAppender.AddIncludes(resolve(efFieldContext), context);
                var names          = GetKeyNames <TReturn>();
                var withArguments  = withIncludes.ApplyGraphQlArguments(context, names);
                return(withArguments
                       .ApplyConnectionContext(
                           context.First,
                           context.After,
                           context.Last,
                           context.Before,
                           context,
                           context.CancellationToken,
                           filters));
            });
            return(builder);
        }
Example #22
0
        FieldType BuildNavigationField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, TReturn?> resolve,
            IEnumerable <string>?includeNames,
            Type?graphType)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);

            //lookup the graph type if not explicitly specified
            graphType ??= GraphTypeFinder.FindGraphType <TReturn>();
            //build field
            return(new FieldType
            {
                Name = name,
                Type = graphType,
                //add the metadata for the tables to be included in the query
                Metadata = IncludeAppender.GetIncludeMetadata(name, includeNames),
                //custom resolve function simply applies the global filters; typically it's a pass-through
                Resolver = new AsyncFieldResolver <TSource, TReturn?>(
                    async context =>
                {
                    var efFieldContext = BuildContext(context);
                    //run resolve function
                    var result = resolve(efFieldContext);
                    //apply global filters and return null if necessary
                    if (await efFieldContext.Filters.ShouldInclude(context.UserContext, result))
                    {
                        return result;
                    }

                    return null;
                })
            });
        }
Example #23
0
        FieldType BuildSingleField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IQueryable <TReturn> > resolve,
            Func <ResolveEfFieldContext <TDbContext, TSource>, TReturn, Task>?mutate,
            IEnumerable <QueryArgument>?arguments,
            Type?graphType,
            bool nullable,
            string?description)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);

            graphType ??= GraphTypeFinder.FindGraphType <TReturn>();
            Type?wrappedType;

            if (nullable)
            {
                wrappedType = graphType;
            }
            else
            {
                wrappedType = typeof(NonNullGraphType <>).MakeGenericType(graphType);
            }

            return(new FieldType
            {
                Name = name,
                Type = wrappedType,
                Description = description,

                Arguments = ArgumentAppender.GetQueryArguments(arguments),

                Resolver = new AsyncFieldResolver <TSource, TReturn?>(
                    async context =>
                {
                    var efFieldContext = BuildContext(context);

                    var names = GetKeyNames <TReturn>();

                    var query = resolve(efFieldContext);
                    if (disableTracking)
                    {
                        query = query.AsNoTracking();
                    }
                    query = includeAppender.AddIncludes(query, context);
                    query = query.ApplyGraphQlArguments(context, names);
                    var single = await query.SingleOrDefaultAsync(context.CancellationToken);

                    if (single != null)
                    {
                        if (await efFieldContext.Filters.ShouldInclude(context.UserContext, single))
                        {
                            if (mutate != null)
                            {
                                await mutate.Invoke(efFieldContext, single);
                            }
                            return single;
                        }
                    }

                    if (nullable)
                    {
                        return null;
                    }

                    throw new("Not found");
                })
            });
Example #24
0
    FieldType BuildSingleField <TSource, TReturn>(
        string name,
        Func <ResolveEfFieldContext <TDbContext, TSource>, IQueryable <TReturn> > resolve,
        Func <ResolveEfFieldContext <TDbContext, TSource>, TReturn, Task>?mutate,
        IEnumerable <QueryArgument>?arguments,
        Type?graphType,
        bool nullable,
        string?description)
        where TReturn : class
    {
        Guard.AgainstWhiteSpace(nameof(name), name);

        graphType ??= GraphTypeFinder.FindGraphType <TReturn>(nullable);

        var hasId = keyNames.ContainsKey(typeof(TReturn));

        return(new()
        {
            Name = name,
            Type = graphType,
            Description = description,

            Arguments = ArgumentAppender.GetQueryArguments(arguments, hasId, false),

            Resolver = new AsyncFieldResolver <TSource, TReturn?>(
                async context =>
            {
                var efFieldContext = BuildContext(context);

                var names = GetKeyNames <TReturn>();

                var query = resolve(efFieldContext);
                if (disableTracking)
                {
                    query = query.AsNoTracking();
                }

                query = includeAppender.AddIncludes(query, context);
                query = query.ApplyGraphQlArguments(context, names, false);

                QueryLogger.Write(query);

                var single = await query.SingleOrDefaultAsync(context.CancellationToken);

                if (single is not null)
                {
                    if (await efFieldContext.Filters.ShouldInclude(context.UserContext, single))
                    {
                        if (mutate is not null)
                        {
                            await mutate.Invoke(efFieldContext, single);
                        }

                        return single;
                    }
                }

                if (nullable)
                {
                    return null;
                }

                throw new ExecutionError("Not found");
            })
        });
    }