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); }
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); }
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); }
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)); }
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>()); }
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); }); }
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)); }
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(); }
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); }