FieldType BuildNavigationField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IEnumerable <TReturn> >?resolve,
            IEnumerable <string>?includeNames,
            Type listGraphType,
            IEnumerable <QueryArgument>?arguments,
            string?description)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);

            var fieldType = new FieldType
            {
                Name        = name,
                Description = description,
                Type        = listGraphType,
                Arguments   = ArgumentAppender.GetQueryArguments(arguments),
                Metadata    = IncludeAppender.GetIncludeMetadata(name, includeNames)
            };

            if (resolve != null)
            {
                fieldType.Resolver = new AsyncFieldResolver <TSource, IEnumerable <TReturn> >(
                    context =>
                {
                    var efFieldContext = BuildContext(context);
                    var result         = resolve(efFieldContext);
                    result             = result.ApplyGraphQlArguments(context);
                    return(efFieldContext.Filters.ApplyFilter(result, context.UserContext));
                });
            }

            return(fieldType);
        }
        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
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (resolve == null)
            {
                throw new ArgumentNullException(nameof(resolve));
            }
            if (pageSize < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(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 =>
            {
                //run the specified resolve function
                var enumerable = resolve(BuildEfContextFromGraphQlContext(context));
                //apply any query filters specified in the arguments
                enumerable = enumerable.ApplyGraphQlArguments(context);
                //apply the global filter on each individually enumerated item
                if (filters != null)
                {
                    enumerable = await 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);
        }
Example #3
0
 FieldType BuildNavigationField <TSource, TReturn>(
     string name,
     Func <ResolveFieldContext <TSource>, IEnumerable <TReturn> > resolve,
     IEnumerable <string> includeNames,
     Type listGraphType,
     IEnumerable <QueryArgument> arguments)
     where TReturn : class
 {
     Guard.AgainstNullWhiteSpace(nameof(name), name);
     Guard.AgainstNull(nameof(resolve), resolve);
     return(new FieldType
     {
         Name = name,
         Type = listGraphType,
         Arguments = ArgumentAppender.GetQueryArguments(arguments),
         Metadata = IncludeAppender.GetIncludeMetadata(name, includeNames),
         Resolver = new AsyncFieldResolver <TSource, IEnumerable <TReturn> >(
             async context =>
         {
             var result = resolve(context);
             result = result.ApplyGraphQlArguments(context);
             return await filters.ApplyFilter(result, context.UserContext);
         })
     });
 }
Example #4
0
        FieldType BuildNavigationField <TSource, TReturn>(
            string name,
            Func <ResolveEfFieldContext <TDbContext, TSource>, IEnumerable <TReturn> > resolve,
            IEnumerable <string> includeNames,
            Type listGraphType,
            IEnumerable <QueryArgument> arguments)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);

            //return the new field type
            return(new FieldType
            {
                Name = name,
                Type = listGraphType,
                //take the arguments manually specified, if any, and append the query arguments
                Arguments = ArgumentAppender.GetQueryArguments(arguments),
                //add the metadata for the tables to be included in the query
                Metadata = IncludeAppender.GetIncludeMetadata(name, includeNames),
                //specify a custom resolve function
                Resolver = new AsyncFieldResolver <TSource, IEnumerable <TReturn> >(
                    context =>
                {
                    var efFieldContext = BuildContext(context);
                    //run the specified resolve function
                    var result = resolve(efFieldContext);
                    //apply any query filters specified in the arguments
                    result = result.ApplyGraphQlArguments(context);
                    //apply the global filter on each individually enumerated item
                    return efFieldContext.Filters.ApplyFilter(result, context.UserContext);
                })
            });
        }
Example #5
0
        public EfGraphQLService(
            IModel model,
            ResolveDbContext <TDbContext> resolveDbContext,
            ResolveFilters resolveFilters = null)
        {
            Guard.AgainstNull(nameof(model), model);
            Guard.AgainstNull(nameof(resolveDbContext), resolveDbContext);
            this.resolveFilters = resolveFilters;

            this.resolveDbContext = resolveDbContext;
            foreach (var entityType in model.GetEntityTypes())
            {
                var primaryKey = entityType.FindPrimaryKey();
                //This can happen for views
                if (primaryKey == null)
                {
                    continue;
                }

                var names = primaryKey.Properties.Select(x => x.Name).ToList();
                keyNames.Add(entityType.ClrType, names);
            }

            includeAppender = new IncludeAppender(NavigationReader.GetNavigationProperties(model));
        }
Example #6
0
        FieldType BuildNavigationField <TSource, TReturn>(
            string name,
            Func <ResolveFieldContext <TSource>, TReturn> resolve,
            IEnumerable <string> includeNames,
            Type graphType,
            IEnumerable <QueryArgument> arguments)
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);
            graphType = GraphTypeFinder.FindGraphType <TReturn>(graphType);
            return(new FieldType
            {
                Name = name,
                Type = graphType,
                Arguments = ArgumentAppender.GetQueryArguments(arguments),
                Metadata = IncludeAppender.GetIncludeMetadata(name, includeNames),
                Resolver = new AsyncFieldResolver <TSource, TReturn>(async context =>
                {
                    var result = resolve(context);
                    if (await filters.ShouldInclude(context.UserContext, result))
                    {
                        return result;
                    }

                    return null;
                })
            });
        }
        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 = 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 #8
0
        ConnectionBuilder <TGraph, TSource> BuildListConnectionField <TSource, TGraph, TReturn>(
            string name,
            Func <ResolveFieldContext <TSource>, IEnumerable <TReturn> > resolve,
            IEnumerable <string> includeName,
            int pageSize)
            where TGraph : ObjectGraphType <TReturn>, IGraphType
            where TReturn : class
        {
            Guard.AgainstNullWhiteSpace(nameof(name), name);
            Guard.AgainstNull(nameof(resolve), resolve);
            Guard.AgainstNegative(nameof(pageSize), pageSize);
            var builder = ConnectionBuilder.Create <TGraph, TSource>();

            builder.PageSize(pageSize);
            builder.Name(name);
            IncludeAppender.SetIncludeMetadata(builder.FieldType, name, includeName);
            builder.Resolve(context =>
            {
                var enumerable = resolve(context);
                enumerable     = enumerable.ApplyGraphQlArguments(context);
                enumerable     = enumerable.Where(item => GlobalFilters.ShouldInclude(context.UserContext, item));
                var page       = enumerable.ToList();

                return(ConnectionConverter.ApplyConnectionContext(
                           page,
                           context.First,
                           context.After,
                           context.Last,
                           context.Before));
            });
            return(builder);
        }
Example #9
0
        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);

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

            builder.PageSize(pageSize).Bidirectional();
            SetField(builder, fieldType);
            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);
        }
Example #10
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);
        }
Example #11
0
        public EfGraphQLService(IModel model, GlobalFilters filters)
        {
            Guard.AgainstNull(nameof(model), model);
            this.filters = filters;
            foreach (var entityType in model.GetEntityTypes())
            {
                var names = entityType.FindPrimaryKey().Properties.Select(x => x.Name).ToList();
                keyNames.Add(entityType.ClrType, names);
            }

            includeAppender = new IncludeAppender(NavigationReader.GetNavigationProperties(model));
        }
    void AddEnumerableConnection <TSource, TGraph, TReturn>(
        ComplexGraphType <TSource> graph,
        string name,
        Func <ResolveEfFieldContext <TDbContext, TSource>, IEnumerable <TReturn> >?resolve,
        int pageSize,
        string?description,
        IEnumerable <QueryArgument>?arguments,
        IEnumerable <string>?includeNames)
        where TGraph : IGraphType
        where TReturn : class
    {
        var builder = ConnectionBuilder.Create <TGraph, TSource>();

        builder.Name(name);

        if (description is not null)
        {
            builder.Description(description);
        }
        builder.PageSize(pageSize).Bidirectional();
        IncludeAppender.SetIncludeMetadata(builder.FieldType, name, includeNames);

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

        if (resolve is not 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));
            });
        }

        // TODO: works around https://github.com/graphql-dotnet/graphql-dotnet/pull/2581/
        builder.FieldType.Type = typeof(NonNullGraphType <ConnectionType <TGraph, EdgeType <TGraph> > >);
        var field = graph.AddField(builder.FieldType);

        field.AddWhereArgument(hasId, arguments);
    }
        public EfGraphQLService(
            IModel model,
            ResolveDbContext <TDbContext> resolveDbContext,
            ResolveFilters?resolveFilters = null)
        {
            Guard.AgainstNull(nameof(model), model);
            Guard.AgainstNull(nameof(resolveDbContext), resolveDbContext);
            this.resolveFilters = resolveFilters;

            this.resolveDbContext = resolveDbContext;

            keyNames = model.GetKeyNames();

            includeAppender = new IncludeAppender(NavigationReader.GetNavigationProperties(model));
        }
        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);
        }
Example #15
0
        ConnectionBuilder <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 ??= GraphTypeFinder.FindGraphType <TReturn>();
            //create a ConnectionBuilder<graphType, TSource> type by invoking the static Create<graphType> method on the generic type
            var builder = GetConnectionBuilder <TSource>(name, graphType);

            //set the page size
            builder.PageSize(pageSize);
            //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);
        }
Example #16
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));
        }
    }
Example #17
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);
        }
        public FieldType AddNavigationListField <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,
            string?description = null)
            where TReturn : class
        {
            Guard.AgainstNull(nameof(graph), graph);
            Guard.AgainstNullWhiteSpace(nameof(name), name);

            var       hasId = keyNames.ContainsKey(typeof(TReturn));
            FieldType field = new()
            {
                Name        = name,
                Description = description,
                Type        = MakeListGraphType <TReturn>(itemGraphType),
                Arguments   = ArgumentAppender.GetQueryArguments(arguments, hasId, true),
            };

            IncludeAppender.SetIncludeMetadata(field, name, includeNames);

            if (resolve != null)
            {
                field.Resolver = new AsyncFieldResolver <TSource, IEnumerable <TReturn> >(
                    context =>
                {
                    var fieldContext = BuildContext(context);
                    var result       = resolve(fieldContext);
                    result           = result.ApplyGraphQlArguments(hasId, context);
                    return(fieldContext.Filters.ApplyFilter(result, context.UserContext));
                });
            }

            return(graph.AddField(field));
        }
Example #19
0
        public EfGraphQLService(IModel model, GlobalFilters filters, Func <object, TDbContext> dbContextFromUserContext)
        {
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }
            this.filters = filters;
            this.dbContextFromUserContext = dbContextFromUserContext ?? throw new ArgumentNullException(nameof(dbContextFromUserContext));
            foreach (var entityType in model.GetEntityTypes())
            {
                var primaryKey = entityType.FindPrimaryKey();
                //This can happen for views
                if (primaryKey == null)
                {
                    continue;
                }

                var names = primaryKey.Properties.Select(x => x.Name).ToList();
                keyNames.Add(entityType.ClrType, names);
            }

            includeAppender = new IncludeAppender(NavigationReader.GetNavigationProperties(model));
        }
 public EfGraphQLService(IModel model, GlobalFilters filters)
 {
     Guard.AgainstNull(nameof(model), model);
     this.filters    = filters;
     includeAppender = new IncludeAppender(NavigationReader.GetNavigationProperties(model));
 }
Example #21
0
 public EntityGraphAdapter(EdmModel model, GlobalFilters filters)
 {
     // Guard.AgainstNull(nameof(model), model);
     this.filters    = filters;
     includeAppender = new IncludeAppender(NavigationReader.GetNavigationProperties(model));
 }
 public EfGraphQLService(DbContext dbContext)
 {
     Guard.AgainstNull(nameof(dbContext), dbContext);
     includeAppender = new IncludeAppender(NavigationReader.GetNavigationProperties(dbContext));
 }
Example #23
0
 public EfGraphQLService(Dictionary <Type, List <Navigation> > navigations)
 {
     Guard.AgainstNull(nameof(navigations), navigations);
     includeAppender = new IncludeAppender(navigations);
 }