Пример #1
0
    public static Resolver DefaultCreateRemoteResolver(ExecutionResultLink link)
    {
        return(async context =>
        {
            var document = CreateDocument(context);
            var variables = context.ExecutionContext.CoercedVariableValues;

            var reader = await link(document, variables, CancellationToken.None);

            while (await reader.WaitToReadAsync(CancellationToken.None))
            {
                if (reader.TryRead(out var executionResult))
                {
                    return new PreExecutedResolverResult(executionResult);
                }
            }

            throw new QueryExecutionException(
                "Could not get result from remote. " +
                "Link channel was closed before result could be read.",
                context.Path,
                context.Selection);
        });

        ExecutableDocument CreateDocument(IResolverContext context)
        {
            return(context.ExecutionContext.Document);
        }
    }
Пример #2
0
        private static Subscriber DefaultCreateRemoteSubscriber(ExecutionResultLink link)
        {
            return(async(context, unsubscribe) =>
            {
                var document = CreateDocument(context);
                var variables = context.ExecutionContext.CoercedVariableValues;

                var result = await link(document, variables, unsubscribe);

                var stream = new EventChannel <ExecutionResult>();

                var _ = Task.Run(async() =>
                {
                    while (await result.WaitToReadAsync(unsubscribe))
                    {
                        if (result.TryRead(out var executionResult))
                        {
                            await stream.WriteAsync(
                                executionResult);
                        }
                    }

                    await result.Completion;
                }, unsubscribe);

                return Resolve.Subscribe(stream, unsubscribe);
            });

            GraphQLDocument CreateDocument(ResolverContext context)
            {
                return(context.ExecutionContext.Document);
            }
        }
Пример #3
0
        /// <summary>
        ///     Execute <see cref="Introspect.DefaultQuery"/> on link
        ///     and import the schema
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="link">Execution link</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static async Task <SchemaBuilder> ImportIntrospectedSchema(
            this SchemaBuilder builder,
            ExecutionResultLink link,
            CancellationToken cancellationToken = default)
        {
            if (link == null)
            {
                throw new ArgumentNullException(nameof(link));
            }

            var channel = await link(
                Parser.ParseDocument(Introspect.DefaultQuery),
                null,
                cancellationToken);

            var result = await channel.ReadAsync(cancellationToken);

            if (result.Errors != null && result.Errors.Any())
            {
                throw new InvalidOperationException(
                          "Failed to execute introspection query. " +
                          $"Errors: {string.Join(", ", result.Errors.Select(e => e.Message))}");
            }

            var json = JsonConvert.SerializeObject(result);

            return(ImportIntrospectedSchema(builder, json));
        }
Пример #4
0
    //todo: use ResolversBuilder.AddLinkedTypes()
    /// <summary>
    ///     Create resolvers for ObjectTypes and ObjectType extensions in <see cref="TypeSystemDocument"/> which
    ///     resolve the values using the given <paramref name="link"/>
    /// </summary>
    /// <param name="remoteTypes"></param>
    /// <param name="link"></param>
    /// <param name="createResolver"></param>
    /// <param name="createSubscriber"></param>
    /// <returns></returns>
    public static ResolversMap CreateLinkResolvers(
        TypeSystemDocument remoteTypes,
        ExecutionResultLink link,
        Func <ExecutionResultLink, Resolver> createResolver     = null,
        Func <ExecutionResultLink, Subscriber> createSubscriber = null)
    {
        if (createResolver == null)
        {
            createResolver = DefaultCreateRemoteResolver;
        }

        if (createSubscriber == null)
        {
            createSubscriber = DefaultCreateRemoteSubscriber;
        }

        var objectDefinitionsAndExtensions = GetObjectDefinitions(remoteTypes);
        var rootTypes = objectDefinitionsAndExtensions.Where(type => RootTypes.Contains(type.Name.Value))
                        .OfType <ObjectDefinition>();

        ResolversMap resolvers = new ResolversMap();

        foreach (var rootType in rootTypes)
        {
            foreach (var field in rootType.Fields)
            {
                if (rootType.Name != "Subscription")
                {
                    resolvers.Add(rootType.Name.Value, field.Name.Value, createResolver(link));
                }
                else
                {
                    resolvers.Add(rootType.Name.Value, field.Name.Value, createSubscriber(link));
                }
            }
        }

        var resolver = DefaultDictionaryResolver();

        foreach (var objectType in objectDefinitionsAndExtensions.Where(type => !RootTypes.Contains(type.Name.Value))
                 .OfType <ObjectDefinition>())
        {
            foreach (var field in objectType.Fields)
            {
                resolvers.Add(objectType.Name.Value, field.Name.Value, resolver);
            }
        }

        return(resolvers);
    }
Пример #5
0
        public static Resolver DefaultCreateRemoteResolver(ExecutionResultLink link)
        {
            return(async context =>
            {
                var document = CreateDocument(context);
                var variables = context.ExecutionContext.CoercedVariableValues;

                var reader = await link(document, variables, CancellationToken.None);

                while (await reader.WaitToReadAsync(CancellationToken.None))
                {
                    if (reader.TryRead(out var executionResult))
                    {
                        if (executionResult.Errors != null && executionResult.Errors.Any())
                        {
                            var first = executionResult.Errors.First();
                            throw new QueryExecutionException(
                                $"{first.Message}",
                                null,
                                path: context.Path,
                                extensions: new Dictionary <string, object>
                            {
                                ["remoteError"] = new
                                {
                                    data = executionResult.Data,
                                    errors = executionResult.Errors,
                                    extensions = executionResult.Extensions
                                }
                            },
                                context.Selection);
                        }

                        return new PreExecutedResolveResult(executionResult.Data);
                    }
                }

                throw new QueryExecutionException(
                    "Could not get result from remote. " +
                    "Link channel was closed before result could be read.",
                    context.Path,
                    context.Selection);
            });

            GraphQLDocument CreateDocument(ResolverContext context)
            {
                return(context.ExecutionContext.Document);
            }
        }
Пример #6
0
        public static Resolver DefaultCreateRemoteResolver(ExecutionResultLink link)
        {
            return(async context =>
            {
                var document = CreateDocument(context);
                var variables = context.ExecutionContext.CoercedVariableValues;

                var reader = await link(document, variables, CancellationToken.None);

                while (await reader.WaitToReadAsync(CancellationToken.None))
                {
                    if (reader.TryRead(out var executionResult))
                    {
                        if (executionResult.Errors != null && executionResult.Errors.Any())
                        {
                            var first = executionResult.Errors.First();
                            throw new CompleteValueException(
                                $"{first.Message}",
                                new[] { context.Selection },
                                locations: new[] { context.Selection.Location },
                                path: context.Path,
                                extensions: new Dictionary <string, object>
                            {
                                ["remoteError"] = new
                                {
                                    data = executionResult.Data,
                                    errors = executionResult.Errors,
                                    extensions = executionResult.Extensions
                                }
                            });
                        }

                        return new PreExecutedResolveResult(executionResult.Data);
                    }
                }

                //todo
                return null;
            });

            GraphQLDocument CreateDocument(ResolverContext context)
            {
                return(context.ExecutionContext.Document);
            }
        }
Пример #7
0
    /// <summary>
    ///     Execute <see cref="Introspect.DefaultQuery" /> on link
    ///     and import the schema
    /// </summary>
    /// <param name="builder"></param>
    /// <param name="link">Execution link</param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public static async Task <SchemaBuilder> ImportIntrospectedSchema(
        this SchemaBuilder builder,
        ExecutionResultLink link,
        CancellationToken cancellationToken = default)
    {
        if (link == null)
        {
            throw new ArgumentNullException(nameof(link));
        }

        var channel = await link(
            Introspect.DefaultQuery,
            null,
            cancellationToken);

        if (channel == null)
        {
            throw new InvalidOperationException(
                      "Failed to execute introspection query. Link returned a null channel.");
        }

        var result = await channel.ReadAsync(cancellationToken);

        if (result == null)
        {
            throw new InvalidOperationException(
                      "Failed to execute introspection query. Link channel read result is null");
        }

        if (result.Errors != null && result.Errors.Any())
        {
            throw new InvalidOperationException(
                      "Failed to execute introspection query. " +
                      $"Errors: {string.Join(", ", result.Errors.Select(e => e.Message))}");
        }

        var json = JsonSerializer.Serialize(result, _jsonOptions);

        return(builder.AddIntrospectedSchema(json));
    }
Пример #8
0
        public static ISchema MakeRemoteExecutable(
            SchemaBuilder builder,
            ExecutionResultLink link,
            Func <ExecutionResultLink, Resolver> createResolver     = null,
            Func <ExecutionResultLink, Subscriber> createSubscriber = null)
        {
            if (createResolver == null)
            {
                createResolver = DefaultCreateRemoteResolver;
            }

            if (createSubscriber == null)
            {
                createSubscriber = DefaultCreateRemoteSubscriber;
            }

            // add remote resolver for query
            if (builder.TryGetType <ObjectType>("Query", out var queryType))
            {
                builder.Connections(connections =>
                {
                    var fields = connections.VisitFields(queryType);

                    foreach (var field in fields)
                    {
                        var resolver = connections.GetOrAddResolver(queryType, field.Key);
                        resolver.Run(createResolver(link));
                    }
                });
            }

            if (builder.TryGetType <ObjectType>("Mutation", out var mutationType))
            {
                builder.Connections(connections =>
                {
                    var fields = connections.VisitFields(mutationType);

                    foreach (var field in fields)
                    {
                        var resolver = connections.GetOrAddResolver(mutationType, field.Key);
                        resolver.Run(createResolver(link));
                    }
                });
            }

            if (builder.TryGetType <ObjectType>("Subscription", out var subscriptionType))
            {
                builder.Connections(connections =>
                {
                    var fields = connections.VisitFields(subscriptionType);

                    foreach (var field in fields)
                    {
                        if (!connections.TryGetSubscriber(subscriptionType, field.Key, out _))
                        {
                            var subscriber = connections.GetOrAddSubscriber(subscriptionType, field.Key);
                            subscriber.Run(createSubscriber(link));
                        }
                    }
                });
            }

            foreach (var objectType in builder.VisitTypes <ObjectType>())
            {
                builder.Connections(connections =>
                {
                    foreach (var field in connections.VisitFields(objectType))
                    {
                        if (!connections.TrGetResolver(objectType, field.Key, out _))
                        {
                            var resolver = connections.GetOrAddResolver(objectType, field.Key);
                            resolver.Run(DefaultDictionaryResolver());
                        }
                    }
                });
            }

            return(builder.Build());
        }