public override async Task <ExecutionResult> ExecuteAsync(ExecutionContext context)
        {
            var rootType = GetOperationRootType(context.Document, context.Schema, context.Operation);
            var rootNode = BuildExecutionRootNode(context, rootType);

            var streams = await ExecuteSubscriptionNodesAsync(context, rootNode.SubFields).ConfigureAwait(false);

            ExecutionResult result = new SubscriptionExecutionResult
            {
                Streams = streams
            }.With(context);

            return(result);
        }
Ejemplo n.º 2
0
        public Subscription(string id,
                            OperationMessagePayload payload,
                            SubscriptionExecutionResult result,
                            IWriterPipeline writer,
                            Action <Subscription> completed,
                            ILogger <Subscription> logger)
        {
            _writer         = writer;
            _completed      = completed;
            _logger         = logger;
            Id              = id;
            OriginalPayload = payload;

            Subscribe(result);
        }
Ejemplo n.º 3
0
        public void Subscribe_to_stream()
        {
            /* Given */
            var id      = "1";
            var payload = new OperationMessagePayload();
            var stream  = new Subject <ExecutionResult>();
            var result  = new SubscriptionExecutionResult
            {
                Streams = new Dictionary <string, IObservable <ExecutionResult> >
                {
                    { "op", stream }
                }
            };

            /* When */
            var sut = new Subscription(id, payload, result, _writer, null, new NullLogger <Subscription>());

            /* Then */
            Assert.True(stream.HasObservers);
        }
Ejemplo n.º 4
0
        public void Subscribe_to_stream()
        {
            /* Given */
            var id      = "1";
            var payload = new OperationMessagePayload();
            var stream  = Substitute.For <IObservable <ExecutionResult> >();
            var result  = new SubscriptionExecutionResult
            {
                Streams = new Dictionary <string, IObservable <ExecutionResult> >
                {
                    { "op", stream }
                }
            };

            /* When */
            var sut = new Subscription(id, payload, result, _writer, null, new NullLogger <Subscription>());


            /* Then */
            stream.Received().Subscribe(Arg.Is <Subscription>(sub => sub.Id == id));
        }
Ejemplo n.º 5
0
        public void Subscribe_to_completed_stream_should_not_throw()
        {
            /* Given */
            var id      = "1";
            var payload = new OperationMessagePayload();
            var subject = new Subject <ExecutionResult>();

            subject.OnCompleted();
            var stream = subject;
            var result = new SubscriptionExecutionResult
            {
                Streams = new Dictionary <string, IObservable <ExecutionResult> >
                {
                    { "op", stream }
                }
            };

            /* When */
            /* Then */
            var sut = new Subscription(id, payload, result, _writer, null, new NullLogger <Subscription>());
        }
Ejemplo n.º 6
0
        public async Task AddSubscription(OperationMessageContext context, SubscriptionExecutionResult result)
        {
            if (result.Errors?.Any() == true)
            {
                await WriteOperationErrorsAsync(context, result.Errors).ConfigureAwait(false);

                return;
            }

            if (result.Streams == null || !result.Streams.Any())
            {
                await WriteOperationErrorsAsync(context, new[]
                {
                    new ExecutionError(
                        $"Could not resolve subsciption stream for {context.Op}")
                }).ConfigureAwait(false);

                return;
            }

            var stream = result.Streams.Values.Single();

            Subscriptions.AddOrUpdate(context.ConnectionId, connectionId =>
            {
                var subscriptions = new ConcurrentDictionary <string, SubscriptionHandle>();

                subscriptions.TryAdd(context.Op.Id,
                                     new SubscriptionHandle(context.Op, stream, context.MessageWriter, new DocumentWriter()));

                return(subscriptions);
            }, (connectionId, subscriptions) =>
            {
                subscriptions.TryAdd(context.Op.Id,
                                     new SubscriptionHandle(context.Op, stream, context.MessageWriter, new DocumentWriter()));

                return(subscriptions);
            });
        }
Ejemplo n.º 7
0
        public async Task Write_Complete_on_unsubscribe()
        {
            /* Given */
            string id      = "1";
            var    payload = new OperationMessagePayload();
            var    result  = new SubscriptionExecutionResult
            {
                Streams = new Dictionary <string, IObservable <ExecutionResult> >
                {
                    { "1", Substitute.For <IObservable <ExecutionResult> >() }
                }
            };

            var sut = new Subscription(id, payload, result, _writer, null, new NullLogger <Subscription>());

            /* When */
            await sut.UnsubscribeAsync();

            /* Then */
            await _writer.Received().SendAsync(
                Arg.Is <OperationMessage>(
                    message => message.Id == id &&
                    message.Type == MessageType.GQL_COMPLETE));
        }
Ejemplo n.º 8
0
        public async Task Unsubscribe_from_stream()
        {
            /* Given */
            string id          = "1";
            var    payload     = new OperationMessagePayload();
            var    unsubscribe = Substitute.For <IDisposable>();
            var    stream      = Substitute.For <IObservable <ExecutionResult> >();

            stream.Subscribe(null).ReturnsForAnyArgs(unsubscribe);
            var result = new SubscriptionExecutionResult
            {
                Streams = new Dictionary <string, IObservable <ExecutionResult> >
                {
                    { "op", stream }
                }
            };
            var sut = new Subscription(id, payload, result, _writer, null, new NullLogger <Subscription>());

            /* When */
            await sut.UnsubscribeAsync();

            /* Then */
            unsubscribe.Received().Dispose();
        }
Ejemplo n.º 9
0
        public override async Task <ExecutionResult> ExecuteAsync(ExecutionContext context)
        {
            var operationType = GetOperationRootType(context.Document, context.Schema, context.Operation);
            var operationNode = BuildExecutionRootNode(context, operationType);

            // By GraphQL spec a subscription operation must have exactly one root node
            var rootNode = operationNode.SubFields.Single().Value;

            var streams = (await ExecuteSubscriptionNodesAsync(context, operationNode.SubFields.Select(x => x.Value))).ToList();

            var mergedStream = streams.Aggregate((prev, next) => prev.Merge(next));

            ExecutionResult result = new SubscriptionExecutionResult
            {
                Streams = new Dictionary <string, IObservable <ExecutionResult> >
                {
                    {
                        // Remark: The key is currently not used anywhere.
                        "Irrelevant",
                        mergedStream.Select(value =>
                        {
                            var executionNode    = BuildExecutionNode(rootNode, rootNode.GraphType, rootNode.Field, rootNode.FieldDefinition, rootNode.Path);
                            executionNode.Source = value;
                            return(executionNode);
                        })
                        .SelectMany(async executionNode =>
                        {
                            foreach (var listener in context.Listeners)
                            {
                                await listener.BeforeExecutionAsync(context.UserContext, context.CancellationToken)
                                .ConfigureAwait(false);
                            }

                            // Execute the whole execution tree and return the result
                            await ExecuteNodeTreeAsync(context, executionNode).ConfigureAwait(false);

                            foreach (var listener in context.Listeners)
                            {
                                await listener.AfterExecutionAsync(context.UserContext, context.CancellationToken)
                                .ConfigureAwait(false);
                            }

                            return(new ExecutionResult
                            {
                                Data = new Dictionary <string, object>
                                {
                                    { executionNode.Name, executionNode.ToValue() }
                                }
                            }.With(context));
                        })
                        .Catch <ExecutionResult, Exception>(exception =>
                                                            Observable.Return(
                                                                new ExecutionResult
                        {
                            Errors = new ExecutionErrors
                            {
                                GenerateError(
                                    context,
                                    $"Could not subscribe to field '{rootNode.Field.Name}' in query '{context.Document.OriginalQuery}'",
                                    rootNode.Field,
                                    rootNode.Path,
                                    exception)
                            }
                        }.With(context)))
                    }
                }
            }.With(context);

            return(result);
        }