public async Task NoOptimization_Defer_Single_Scalar_Field() { IExecutionResult result = await new ServiceCollection() .AddStarWarsRepositories() .AddGraphQL() .AddStarWarsTypes() .ExecuteRequestAsync( @"{ hero(episode: NEW_HOPE) { id ... @defer { name } } }"); IResponseStream stream = Assert.IsType <DeferredQueryResult>(result); var results = new StringBuilder(); await foreach (IQueryResult payload in stream.ReadResultsAsync()) { results.AppendLine(payload.ToJson()); results.AppendLine(); } results.ToString().MatchSnapshot(); }
public async Task Stream_Nodes() { IExecutionResult result = await new ServiceCollection() .AddStarWarsRepositories() .AddGraphQL() .AddStarWarsTypes() .ExecuteRequestAsync( @"{ hero(episode: NEW_HOPE) { id ... @defer(label: ""friends"") { friends { nodes @stream(initialCount: 1) { id name } } } } }"); IResponseStream stream = Assert.IsType <DeferredQueryResult>(result); var results = new StringBuilder(); await foreach (IQueryResult payload in stream.ReadResultsAsync()) { results.AppendLine(payload.ToJson()); results.AppendLine(); } results.ToString().MatchSnapshot(); }
private async Task ExecuteOperationBatchAsync( HttpContext context, IServiceProvider services, GraphQLRequest request, IReadOnlyList <string> operationNames) { IReadOnlyList <IReadOnlyQueryRequest> requestBatch = await BuildBatchRequestAsync( context, services, request, operationNames) .ConfigureAwait(false); IResponseStream responseStream = await _batchExecutor .ExecuteAsync(requestBatch, context.GetCancellationToken()) .ConfigureAwait(false); SetResponseHeaders( context.Response, _streamSerializer.ContentType); await _streamSerializer.SerializeAsync( responseStream, context.Response.Body, context.GetCancellationToken()) .ConfigureAwait(false); }
public SubscriptionSession( CancellationTokenSource session, ISocketSessionInterceptor sessionInterceptor, ISocketConnection connection, IResponseStream responseStream, ISubscription subscription, IExecutionDiagnosticEvents diagnosticEvents, string clientSubscriptionId) { _session = session ?? throw new ArgumentNullException(nameof(session)); _sessionInterceptor = sessionInterceptor ?? throw new ArgumentNullException(nameof(sessionInterceptor)); _connection = connection ?? throw new ArgumentNullException(nameof(connection)); _responseStream = responseStream ?? throw new ArgumentNullException(nameof(responseStream)); _diagnosticEvents = diagnosticEvents ?? throw new ArgumentNullException(nameof(diagnosticEvents)); Subscription = subscription ?? throw new ArgumentNullException(nameof(subscription)); Id = clientSubscriptionId ?? throw new ArgumentNullException(nameof(clientSubscriptionId)); _sessionToken = _session.Token; Task.Factory.StartNew( SendResultsAsync, _sessionToken, TaskCreationOptions.LongRunning, TaskScheduler.Default); }
public Task SerializeAsync( IResponseStream responseStream, Stream outputStream) => SerializeAsync( responseStream, outputStream, CancellationToken.None);
public async Task SubscribeToReview() { // arrange Schema schema = CreateSchema(); // act IResponseStream responseStream = (IResponseStream)await schema.ExecuteAsync( "subscription { onCreateReview(episode: NEWHOPE) " + "{ stars } }"); // assert IExecutionResult result = await schema.ExecuteAsync(@" mutation { createReview(episode: NEWHOPE, review: { stars: 5 commentary: ""foo"" }) { stars commentary } }"); IQueryExecutionResult eventResult; using (var cts = new CancellationTokenSource(2000)) { eventResult = await responseStream.ReadAsync(); } eventResult.Snapshot(); }
public async Task NoOptimization_Spread_Defer() { IExecutionResult result = await new ServiceCollection() .AddStarWarsRepositories() .AddGraphQL() .AddStarWarsTypes() .ExecuteRequestAsync( @"{ hero(episode: NEW_HOPE) { id ... deferred @defer(label: ""friends"") } } fragment deferred on Character { friends { nodes { id } } }"); IResponseStream stream = Assert.IsType <DeferredQueryResult>(result); var results = new StringBuilder(); await foreach (IQueryResult payload in stream.ReadResultsAsync()) { results.AppendLine(payload.ToJson()); results.AppendLine(); } results.ToString().MatchSnapshot(); }
private async Task WriteNextResultAsync( IResponseStream responseStream, Stream outputStream, bool delimiter, CancellationToken cancellationToken) { IReadOnlyQueryResult result = await responseStream.ReadAsync(cancellationToken) .ConfigureAwait(false); if (result == null) { return; } if (delimiter) { outputStream.WriteByte(_comma); } await _serializer.SerializeAsync( result, outputStream, cancellationToken) .ConfigureAwait(false); await outputStream.FlushAsync(cancellationToken) .ConfigureAwait(false); }
private async Task WriteStreamAsync( IResponseStream responseStream, Stream outputStream, CancellationToken cancellationToken = default) { var delimiter = false; await outputStream .WriteAsync(new[] { _leftBracket }, 0, 1, cancellationToken) .ConfigureAwait(false); await foreach (IQueryResult result in responseStream.ReadResultsAsync() .WithCancellation(cancellationToken) .ConfigureAwait(false)) { await WriteNextResultAsync( result, outputStream, delimiter, cancellationToken) .ConfigureAwait(false); delimiter = true; } await outputStream .WriteAsync(new[] { _rightBracket }, 0, 1, cancellationToken) .ConfigureAwait(false); }
private async Task ExecuteQueryBatchAsync( HttpContext context, IServiceProvider services, IReadOnlyList <GraphQLRequest> batch) { IReadOnlyList <IReadOnlyQueryRequest> requestBatch = await BuildBatchRequestAsync(context, services, batch) .ConfigureAwait(false); SetResponseHeaders( context.Response, _streamSerializer.ContentType); var schemaName = await _schemaNameProvider(context).ConfigureAwait(false); var _batchExecutor = _batchExecutorProvider.GetExecutor(schemaName); IResponseStream responseStream = await _batchExecutor .ExecuteAsync(requestBatch, context.GetCancellationToken()) .ConfigureAwait(false); await _streamSerializer.SerializeAsync( responseStream, context.Response.Body, context.GetCancellationToken()) .ConfigureAwait(false); }
public SubscriptionSession( ISocketConnection connection, IResponseStream responseStream, ISubscription subscription, IDiagnosticEvents diagnosticEvents, string clientSubscriptionId) { _connection = connection ?? throw new ArgumentNullException(nameof(connection)); _responseStream = responseStream ?? throw new ArgumentNullException(nameof(responseStream)); _diagnosticEvents = diagnosticEvents ?? throw new ArgumentNullException(nameof(diagnosticEvents)); Subscription = subscription ?? throw new ArgumentNullException(nameof(subscription)); Id = clientSubscriptionId ?? throw new ArgumentNullException(nameof(clientSubscriptionId)); _cts = CancellationTokenSource.CreateLinkedTokenSource(_connection.RequestAborted); Task.Factory.StartNew( SendResultsAsync, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); }
public async Task Stream_With_DataLoader_InitialCount_1() { IExecutionResult result = await new ServiceCollection() .AddGraphQL() .AddQueryType <QueryWithDataLoader>() .AddDataLoader <PersonsGroupDataLoader>() .ExecuteRequestAsync( @"{ persons @stream(initialCount: 1) { name } }"); IResponseStream stream = Assert.IsType <DeferredQueryResult>(result); var results = new StringBuilder(); await foreach (IQueryResult payload in stream.ReadResultsAsync()) { results.AppendLine(payload.ToJson()); results.AppendLine(); } results.ToString().MatchSnapshot(); }
public Subscription( IWebSocketContext context, IResponseStream responseStream, string id) { _context = context ?? throw new ArgumentNullException(nameof(context)); _responseStream = responseStream ?? throw new ArgumentNullException(nameof(responseStream)); Id = id ?? throw new ArgumentNullException(nameof(id)); Task.Run(SendResultsAsync); }
private async Task ReceiveMessagesAsync() { Console.WriteLine("start listening for typing ..."); IResponseStream <IOnUserIsTyping> messageStream = await _chatClient.OnUserIsTypingAsync(); Console.WriteLine("started listening for typing ..."); await foreach (IOperationResult <IOnUserIsTyping> response in messageStream) { Console.WriteLine("evaluating message ..."); if (!response.HasErrors && response.Data is { } &&
public Task SerializeAsync( IResponseStream responseStream, Stream outputStream, CancellationToken cancellationToken = default) { if (responseStream is null) { throw new ArgumentNullException(nameof(responseStream)); } if (outputStream is null) { throw new ArgumentNullException(nameof(outputStream)); } return(WriteResponseStreamAsync(responseStream, outputStream, cancellationToken)); }
public Subscription( ISocketConnection connection, IResponseStream responseStream, string id) { _connection = connection ?? throw new ArgumentNullException(nameof(connection)); _responseStream = responseStream ?? throw new ArgumentNullException(nameof(responseStream)); Id = id ?? throw new ArgumentNullException(nameof(id)); Task.Factory.StartNew( SendResultsAsync, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); }
private static async Task HandleStreamResultAsync( ISocketConnection connection, DataStartMessage message, IResponseStream responseStream, CancellationToken cancellationToken) { await foreach (IQueryResult queryResult in responseStream.ReadResultsAsync() .WithCancellation(cancellationToken)) { await connection.SendAsync( new DataResultMessage(message.Id, queryResult).Serialize(), cancellationToken); } await connection.SendAsync( new DataCompleteMessage(message.Id).Serialize(), cancellationToken); }
public async Task SerializeAsync( IResponseStream responseStream, Stream outputStream, CancellationToken cancellationToken) { outputStream.WriteByte(_leftBracket); await WriteNextResultAsync( responseStream, outputStream, false, cancellationToken) .ConfigureAwait(false); while (!responseStream.IsCompleted) { await WriteNextResultAsync( responseStream, outputStream, true, cancellationToken) .ConfigureAwait(false); } outputStream.WriteByte(_rightBracket); }
public async Task SerializeAsync( IResponseStream responseStream, Stream outputStream, CancellationToken cancellationToken) { bool delimiter = false; await outputStream.WriteAsync(new[] { _leftBracket }, 0, 1).ConfigureAwait(false); await foreach (IReadOnlyQueryResult result in responseStream.WithCancellation(cancellationToken)) { await WriteNextResultAsync( result, outputStream, delimiter, cancellationToken) .ConfigureAwait(false); delimiter = true; } await outputStream.WriteAsync(new[] { _rightBracket }, 0, 1).ConfigureAwait(false); }
public async Task WriteResponseStreamAsync( IResponseStream responseStream, Stream outputStream, CancellationToken cancellationToken = default) { await foreach (IQueryResult result in responseStream.ReadResultsAsync() .WithCancellation(cancellationToken) .ConfigureAwait(false)) { await WriteResultAsync(result, outputStream, cancellationToken) .ConfigureAwait(false); } // After the last part of the multipart response is sent, the terminating // boundary ----- is sent, followed by a CRLF await outputStream.WriteAsync(End, 0, End.Length, cancellationToken) .ConfigureAwait(false); await outputStream.WriteAsync(CrLf, 0, CrLf.Length, cancellationToken) .ConfigureAwait(false); }
public async Task Handle_Stop_Subscription() { // arrange var connection = new SocketConnectionMock(); var services = new ServiceCollection(); services.AddInMemorySubscriptionProvider(); services.AddStarWarsRepositories(); IQueryExecutor executor = SchemaBuilder.New() .AddServices(services.BuildServiceProvider()) .AddStarWarsTypes() .Create() .MakeExecutable(); DocumentNode query = Utf8GraphQLParser.Parse( "subscription { onReview(episode: NEWHOPE) { stars } }"); IResponseStream stream = (IResponseStream)await executor.ExecuteAsync( "subscription { onReview(episode: NEWHOPE) { stars } }"); var subscription = new Subscription(connection, stream, "123"); connection.Subscriptions.Register(subscription); var handler = new DataStopMessageHandler(); var message = new DataStopMessage("123"); // act await handler.HandleAsync( connection, message, CancellationToken.None); // assert Assert.Empty(connection.Subscriptions); }
public async Task Do_Not_Stream_Nodes() { IExecutionResult result = await new ServiceCollection() .AddStarWarsRepositories() .AddGraphQL() .AddStarWarsTypes() .ExecuteRequestAsync( QueryRequestBuilder.New() .SetQuery( @"query($stream: Boolean) { hero(episode: NEW_HOPE) { id ... @defer(label: ""friends"") { friends { nodes @stream(initialCount: 1, if: $stream) { id name } } } } }") .SetVariableValue("stream", false) .Create()); IResponseStream stream = Assert.IsType <DeferredQueryResult>(result); var results = new StringBuilder(); await foreach (IQueryResult payload in stream.ReadResultsAsync()) { results.AppendLine(payload.ToJson()); results.AppendLine(); } results.ToString().MatchSnapshot(); }
public async Task Serialize_Response_Stream() { // arrange IExecutionResult result = await new ServiceCollection() .AddStarWarsRepositories() .AddGraphQL() .AddStarWarsTypes() .ExecuteRequestAsync( @"{ hero(episode: NEW_HOPE) { id ... @defer(label: ""friends"") { friends { nodes { id ... @defer { name } } } } } }"); IResponseStream stream = Assert.IsType <DeferredQueryResult>(result); var memoryStream = new MemoryStream(); var serializer = new MultiPartResponseStreamSerializer(); // act await serializer.SerializeAsync(stream, memoryStream, CancellationToken.None); // assert memoryStream.Seek(0, SeekOrigin.Begin); new StreamReader(memoryStream).ReadToEnd().MatchSnapshot(); }
private async Task WriteResponseStreamAsync( IResponseStream responseStream, Stream outputStream, CancellationToken cancellationToken = default) { await WriteNextAsync(outputStream, cancellationToken).ConfigureAwait(false); await foreach (IQueryResult result in responseStream.ReadResultsAsync() .WithCancellation(cancellationToken) .ConfigureAwait(false)) { await WriteResultAsync(result, outputStream, cancellationToken) .ConfigureAwait(false); result.Dispose(); if (result.HasNext ?? false) { await WriteNextAsync(outputStream, cancellationToken).ConfigureAwait(false); await outputStream.FlushAsync(cancellationToken) .ConfigureAwait(false); } else { // we will exit the foreach even if there are more items left // since we were signaled that there are no more items break; } } await WriteEndAsync(outputStream, cancellationToken).ConfigureAwait(false); await outputStream.FlushAsync(cancellationToken) .ConfigureAwait(false); }
public async Task Convert_List_To_Single_Value_With_Converters() { // arrange var serviceCollection = new ServiceCollection(); serviceCollection .AddSingleton <ISchema>(sp => SchemaBuilder.New() .AddServices(sp) .AddExportDirectiveType() .AddQueryType(d => { d.Name("Query"); d.Field("foo") .Argument("bar", a => a.Type <ListType <StringType> >()) .Type <ListType <StringType> >() .Resolver <List <string> >(c => { var list = c.Argument <List <string> >("bar"); list.Add("789"); return(list); }); d.Field("baz") .Argument("bar", a => a.Type <StringType>()) .Resolver(c => c.Argument <string>("bar")); }) .Create()) .AddSingleton <IBatchQueryExecutor, BatchQueryExecutor>(); QueryExecutionBuilder.BuildDefault(serviceCollection); IServiceProvider services = serviceCollection.BuildServiceProvider(); var executor = services.GetService <IBatchQueryExecutor>(); // act var batch = new List <IReadOnlyQueryRequest> { QueryRequestBuilder.New() .SetQuery( @"query foo1($b1: [String]) { foo(bar: $b1) @export(as: ""b2"") }") .AddVariableValue("b1", new[] { "123" }) .Create(), QueryRequestBuilder.New() .SetQuery( @"query foo2($b2: String) { baz(bar: $b2) }") .Create() }; IResponseStream stream = await executor.ExecuteAsync(batch, CancellationToken.None); var results = new List <IReadOnlyQueryResult>(); await foreach (IReadOnlyQueryResult result in stream) { if (result != null) { results.Add(result); } } Assert.Collection(results, r => r.MatchSnapshot(new SnapshotNameExtension("1")), r => r.MatchSnapshot(new SnapshotNameExtension("2"))); }
public async Task Handle_Subscription_DataReceived_And_Completed() { // arrange var connection = new SocketConnectionMock(); var services = new ServiceCollection(); services.AddInMemorySubscriptionProvider(); services.AddStarWarsRepositories(); IQueryExecutor executor = SchemaBuilder.New() .AddServices(services.BuildServiceProvider()) .AddStarWarsTypes() .Create() .MakeExecutable(); DocumentNode query = Utf8GraphQLParser.Parse( "subscription { onReview(episode: NEWHOPE) { stars } }"); var handler = new DataStartMessageHandler(executor, null); var message = new DataStartMessage( "123", new GraphQLRequest(query)); // act await handler.HandleAsync( connection, message, CancellationToken.None); // assert Assert.Empty(connection.SentMessages); Assert.NotEmpty(connection.Subscriptions); IResponseStream stream = (IResponseStream)await executor.ExecuteAsync( "subscription { onReview(episode: NEWHOPE) { stars } }"); await executor.ExecuteAsync(@" mutation { createReview(episode:NEWHOPE review: { commentary: ""foo"" stars: 5 }) { stars } }"); IReadOnlyQueryResult result = await stream.ReadAsync(); await Task.Delay(2000); Assert.Collection(connection.SentMessages, t => { Assert.True(t.SequenceEqual( new DataResultMessage(message.Id, result).Serialize())); }); }
public async Task ExecuteExportScalar() { // arrange var serviceCollection = new ServiceCollection(); serviceCollection .AddStarWarsRepositories() .AddSingleton <IBatchQueryExecutor, BatchQueryExecutor>(); QueryExecutionBuilder.BuildDefault(serviceCollection); serviceCollection.AddSingleton <ISchema>(sp => SchemaBuilder.New() .AddStarWarsTypes() .AddExportDirectiveType() .AddServices(sp) .Create()); IServiceProvider services = serviceCollection.BuildServiceProvider(); var executor = services.GetService <IBatchQueryExecutor>(); // act var batch = new List <IReadOnlyQueryRequest> { QueryRequestBuilder.New() .SetQuery( @" query getHero { hero(episode: EMPIRE) { id @export } }") .Create(), QueryRequestBuilder.New() .SetQuery( @" query getHuman { human(id: $id) { name } }") .Create() }; IResponseStream stream = await executor.ExecuteAsync(batch, CancellationToken.None); var results = new List <IReadOnlyQueryResult>(); await foreach (IReadOnlyQueryResult result in stream) { if (result != null) { results.Add(result); } } Assert.Collection(results, r => r.MatchSnapshot(new SnapshotNameExtension("1")), r => r.MatchSnapshot(new SnapshotNameExtension("2"))); }
public async Task ExecuteExportObjectList() { // arrange var serviceCollection = new ServiceCollection(); serviceCollection .AddSingleton <ISchema>(sp => SchemaBuilder.New() .AddServices(sp) .AddExportDirectiveType() .AddDocumentFromString( @" type Query { foo(f: [FooInput]) : [Foo] } type Foo { bar: String! } input FooInput { bar: String! } ") .AddResolver("Query", "foo", c => { var list = c.Argument <List <object> >("f"); if (list == null) { return(new List <object> { new Dictionary <string, object> { { "bar", "123" } } }); } else { list.Add(new Dictionary <string, object> { { "bar", "456" } }); return(list); } }) .Use(next => context => { object o = context.Parent <object>(); if (o is Dictionary <string, object> d && d.TryGetValue( context.ResponseName, out object v)) { context.Result = v; } return(next(context)); }) .Create()) .AddSingleton <IBatchQueryExecutor, BatchQueryExecutor>(); QueryExecutionBuilder.BuildDefault(serviceCollection); IServiceProvider services = serviceCollection.BuildServiceProvider(); var executor = services.GetService <IBatchQueryExecutor>(); // act var batch = new List <IReadOnlyQueryRequest> { QueryRequestBuilder.New() .SetQuery( @"{ foo @export(as: ""b"") { bar } }") .Create(), QueryRequestBuilder.New() .SetQuery( @"{ foo(f: $b) { bar } }") .Create() }; IResponseStream stream = await executor.ExecuteAsync(batch, CancellationToken.None); var results = new List <IReadOnlyQueryResult>(); await foreach (IReadOnlyQueryResult result in stream) { if (result != null) { results.Add(result); } } Assert.Collection(results, r => r.MatchSnapshot(new SnapshotNameExtension("1")), r => r.MatchSnapshot(new SnapshotNameExtension("2"))); }
private async Task SendResultsAsync() { await using IResponseStream responseStream = _responseStream; CancellationToken cancellationToken = _sessionToken; try { await foreach (IQueryResult result in responseStream.ReadResultsAsync().WithCancellation(cancellationToken)) { using (result) { if (!cancellationToken.IsCancellationRequested && !_connection.Closed) { await _connection.SendAsync( new DataResultMessage(Id, result), cancellationToken); } } } if (!cancellationToken.IsCancellationRequested && !_connection.Closed) { await _connection.SendAsync(new DataCompleteMessage(Id), cancellationToken); } } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { } catch (ObjectDisposedException) { } catch (Exception ex) when(!cancellationToken.IsCancellationRequested) { if (!_connection.Closed) { try { try { await _connection.SendAsync( new DataResultMessage(Id, UnknownSubscriptionError(ex)), cancellationToken); } finally { await _connection.SendAsync( new DataCompleteMessage(Id), cancellationToken); await _sessionInterceptor.OnCloseAsync(_connection, cancellationToken); } } catch { // suppress all errors, so original exception can be rethrown } } _diagnosticEvents.SubscriptionTransportError(Subscription, ex); } finally { // completed should be always invoked to be ensure that disposed subscription is // removed from subscription manager Completed?.Invoke(this, EventArgs.Empty); Dispose(); } }
public async Task ExecuteExportObject() { // arrange var serviceCollection = new ServiceCollection(); serviceCollection.AddInMemorySubscriptionProvider(); serviceCollection .AddStarWarsRepositories() .AddSingleton <IBatchQueryExecutor, BatchQueryExecutor>(); QueryExecutionBuilder.BuildDefault(serviceCollection); serviceCollection.AddSingleton <ISchema>(sp => SchemaBuilder.New() .AddStarWarsTypes() .AddExportDirectiveType() .AddServices(sp) .Create()); IServiceProvider services = serviceCollection.BuildServiceProvider(); var executor = services.GetService <IBatchQueryExecutor>(); // act var batch = new List <IReadOnlyQueryRequest> { QueryRequestBuilder.New() .SetQuery( @" mutation firstReview { createReview( episode: NEWHOPE review: { commentary: ""foo"", stars: 4 }) @export(as: ""r"") { commentary stars } }") .Create(), QueryRequestBuilder.New() .SetQuery( @" mutation secondReview { createReview( episode: EMPIRE review: $r) { commentary stars } }") .Create() }; IResponseStream stream = await executor.ExecuteAsync(batch, CancellationToken.None); var results = new List <IReadOnlyQueryResult>(); await foreach (IReadOnlyQueryResult result in stream) { if (result != null) { results.Add(result); } } Assert.Collection(results, r => r.MatchSnapshot(new SnapshotNameExtension("1")), r => r.MatchSnapshot(new SnapshotNameExtension("2"))); }