private static void VerifyRequestContents(IRequestExecutor executor, string queryString) { executor.Received() .ExecuteAsync( Arg.Is<IHttpRequest>(request => request.CanonicalUri.ToString().EndsWith(queryString)), Arg.Any<CancellationToken>()); }
internal static IInternalDataStore Create(IRequestExecutor requestExecutor = null, ICacheProvider cacheProvider = null, ILogger logger = null, IClient client = null) { return new DefaultDataStore( client: client ?? Substitute.For<IClient>(), requestExecutor: requestExecutor ?? Substitute.For<IRequestExecutor>(), baseUrl: BaseUrl, serializer: Serializers.Create().JsonNetSerializer().Build(), logger: logger ?? new NullLogger(), userAgentBuilder: new FakeUserAgentBuilder(), cacheProvider: cacheProvider ?? Caches.NewDisabledCacheProvider(), identityMapExpiration: TimeSpan.FromMinutes(10)); }
public StubRequestExecutor(string resourceJson, IClientApiKey clientApiKey = null) { this.resourceJson = resourceJson; this.fakeRequestExecutor = Substitute.For<IRequestExecutor>(); // API Key this.fakeRequestExecutor.ApiKey.Returns(clientApiKey); // All GETs return 200 OK this.fakeRequestExecutor .ExecuteAsync( Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Get), Arg.Any<CancellationToken>()) .Returns( Task.FromResult(new DefaultHttpResponse(200, "OK", new HttpHeaders(), resourceJson, "application/json", transportError: false) as IHttpResponse)); this.fakeRequestExecutor .Execute( Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Get)) .Returns(new DefaultHttpResponse(200, "OK", new HttpHeaders(), resourceJson, "application/json", transportError: false)); // All POSTs return 201 Created this.fakeRequestExecutor .ExecuteAsync( Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Post), Arg.Any<CancellationToken>()) .Returns( Task.FromResult(new DefaultHttpResponse(201, "Created", new HttpHeaders(), resourceJson, "application/json", transportError: false) as IHttpResponse)); this.fakeRequestExecutor .Execute( Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Post)) .Returns(new DefaultHttpResponse(201, "Created", new HttpHeaders(), resourceJson, "application/json", transportError: false)); // All DELETEs return 204 No Content this.fakeRequestExecutor .ExecuteAsync( Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Delete), Arg.Any<CancellationToken>()) .Returns( Task.FromResult(new DefaultHttpResponse(204, "No Content", new HttpHeaders(), null, null, transportError: false) as IHttpResponse)); this.fakeRequestExecutor .Execute( Arg.Is<IHttpRequest>(req => req.Method == HttpMethod.Delete)) .Returns(new DefaultHttpResponse(204, "No Content", new HttpHeaders(), null, null, transportError: false)); }
public async Task Create_ObjectEnum_OrderBy() { // arrange IRequestExecutor tester = _cache.CreateSchema <Bar, BarSortType>(_barEntities); // act IExecutionResult res1 = await tester.ExecuteAsync( QueryRequestBuilder.New() .SetQuery( "{ root(order: { foo: { barEnum: ASC}}) " + "{ foo{ barEnum}}}") .Create()); IExecutionResult res2 = await tester.ExecuteAsync( QueryRequestBuilder.New() .SetQuery( "{ root(order: { foo: { barEnum: DESC}}) " + "{ foo{ barEnum}}}") .Create()); // assert res1.MatchSqlSnapshot("ASC"); res2.MatchSqlSnapshot("DESC"); }
public async Task AutoMerge_Execute_Computed() { // arrange IHttpClientFactory httpClientFactory = Context.CreateDefaultRemoteSchemas(); IRequestExecutor executor = await new ServiceCollection() .AddSingleton(httpClientFactory) .AddGraphQL() .AddRemoteSchema(Context.ContractSchema) .AddRemoteSchema(Context.CustomerSchema) .AddTypeExtensionsFromString( @"extend type Customer { foo: String @computed(dependantOn: [""id"", ""name""]) }") .MapField( new FieldReference("Customer", "foo"), next => context => { var obj = context.Parent <IReadOnlyDictionary <string, object> >(); context.Result = obj["name"] + "_" + obj["id"]; return(default); })
public async Task MiddlewareConfig_MapWithClassFactory() { // arrange ISchema schema = Schema.Create( "type Query { a: String b: String }", c => c.Map( new FieldReference("Query", "a"), (services, next) => new TestFieldMiddleware(next)) .Map( new FieldReference("Query", "b"), next => context => { context.Result = "456"; return(default(ValueTask)); })); IRequestExecutor executor = schema.MakeExecutable(); // act IExecutionResult result = await executor.ExecuteAsync("{ a b }"); // assert result.ToJson().MatchSnapshot(); }
public async Task Attribute_Nested_List_With_Field_Settings_Skip_2() { Snapshot.FullName(); IRequestExecutor executor = await new ServiceCollection() .AddGraphQL() .AddQueryType <QueryAttr>() .Services .BuildServiceProvider() .GetRequestExecutorAsync(); await executor .ExecuteAsync(@" { nestedObjectList(first: 2) { edges { node { bar } cursor } nodes { bar } pageInfo { hasNextPage hasPreviousPage startCursor endCursor } totalCount } }") .MatchSnapshotAsync(); }
public async Task SubscribeToReview() { // arrange IRequestExecutor executor = await CreateExecutorAsync(); // act var subscriptionResult = (ISubscriptionResult)await executor.ExecuteAsync( "subscription { onReview(episode: NEW_HOPE) " + "{ stars } }"); // assert await executor.ExecuteAsync(@" mutation { createReview(episode: NEW_HOPE, review: { stars: 5 commentary: ""foo"" }) { stars commentary } }"); IReadOnlyQueryResult eventResult = null; using (var cts = new CancellationTokenSource(2000)) { await foreach (IQueryResult queryResult in subscriptionResult.ReadResultsAsync().WithCancellation(cts.Token)) { var item = (IReadOnlyQueryResult)queryResult; eventResult = item; break; } } eventResult?.MatchSnapshot(); }
public async Task Input_Value_Null_As_Variable() { // arrange ISchema schema = SchemaBuilder.New() .AddQueryType(d => d .Name("Query") .Field("foo") .Type <AnyType>() .Argument("input", a => a.Type <AnyType>()) .Resolver(ctx => ctx.ArgumentValue <object>("input"))) .Create(); IRequestExecutor executor = schema.MakeExecutable(); // act IExecutionResult result = await executor.ExecuteAsync( QueryRequestBuilder.New() .SetQuery("query ($foo: Any) { foo(input: $foo) }") .SetVariableValue("foo", null) .Create()); // assert result.ToJson().MatchSnapshot(); }
public async Task Execute_Ok_StatusCode_With_Error_On_DownStream_Request() { // arrange IHttpClientFactory httpClientFactory = CreateDefaultRemoteSchemas(); IRequestExecutor executor = await new ServiceCollection() .AddSingleton(httpClientFactory) .AddGraphQL() .AddQueryType(d => d.Name("Query")) .AddRemoteSchema(_accounts) .AddRemoteSchema(_inventory) .AddRemoteSchema(_products) .AddRemoteSchema(_reviews) .BuildRequestExecutorAsync(); // act IExecutionResult result = await executor.ExecuteAsync( @"{ a: topProducts(first: 1) { upc error } b: topProducts(first: 2) { upc error } }"); // assert Assert.Collection( result.Errors !.Select(t => t.Path !.ToString()).OrderBy(t => t), t => Assert.Equal("/a[0]/error", t), t => Assert.Equal("/b[0]/error", t), t => Assert.Equal("/b[1]/error", t)); }
public async Task Should_NotInitializeObject_When_ResultOfLeftJoinIsNull_TwoFields() { // arrange IRequestExecutor tester = _cache.CreateSchema(_barWithoutRelation, OnModelCreating); // act // assert IExecutionResult res1 = await tester.ExecuteAsync( QueryRequestBuilder.New() .SetQuery( @" { root { id foo { id barEnum } } }") .Create()); res1.MatchSqlSnapshot(); }
public async Task Simple_StringList_Default_Items() { Snapshot.FullName(); IRequestExecutor executor = await CreateSchemaAsync(); IExecutionResult result = await executor .ExecuteAsync( @" { foos { items { bar } pageInfo { hasNextPage hasPreviousPage } totalCount } }"); result.MatchDocumentSnapshot(); }
public ConnectionFactory() { IRestSharpFactory restSharpFactory = new RestSharpFactory(); IResponseVerifier responseVerifier = new ResponseVerifier(); _requestExecutor = new RequestExecutor(restSharpFactory, responseVerifier); }
public HandshakeClient(IRequestExecutor requestExecutor) { _requestExecutor = requestExecutor; }
public ChannelClient(IRequestExecutor requestExecutor) { _requestExecutor = requestExecutor; }
public static IRequestExecutorBuilder AddRemoteSchema( this IRequestExecutorBuilder builder, NameString schemaName, Func <IServiceProvider, CancellationToken, ValueTask <DocumentNode> > loadSchema, bool ignoreRootTypes = false) { if (builder is null) { throw new ArgumentNullException(nameof(builder)); } if (loadSchema is null) { throw new ArgumentNullException(nameof(loadSchema)); } schemaName.EnsureNotEmpty(nameof(schemaName)); // first we add a full GraphQL schema and executor that represents the remote schema. // This remote schema will be used by the stitching engine to execute queries against // this schema and also to lookup types in order correctly convert between scalars. builder .AddGraphQL(schemaName) .ConfigureSchemaServices(services => { services.TryAddSingleton( sp => new HttpRequestClient( sp.GetApplicationService <IHttpClientFactory>(), sp.GetRequiredService <IErrorHandler>(), sp.GetRequiredService <IHttpStitchingRequestInterceptor>())); services.TryAddSingleton < IHttpStitchingRequestInterceptor, HttpStitchingRequestInterceptor>(); }) .ConfigureSchemaAsync( async(services, schemaBuilder, cancellationToken) => { // No we need to load the schema document. DocumentNode document = await loadSchema(services, cancellationToken) .ConfigureAwait(false); document = document.RemoveBuiltInTypes(); // The document is used to create a SDL-first schema ... schemaBuilder.AddDocument(document); // ... which will fail if any resolver is actually used ... // todo : how to bind resolvers schemaBuilder.Use(next => context => throw new NotSupportedException()); }) // ... instead we are using a special request pipeline that does everything like // the standard pipeline except the last middleware will not start the execution // algorithms but delegate the request via HTTP to the downstream schema. .UseHttpRequestPipeline(); // Next, we will register a request executor proxy with the stitched schema, // that the stitching runtime will use to send requests to the schema representing // the downstream service. builder .ConfigureSchemaAsync(async(services, schemaBuilder, cancellationToken) => { IInternalRequestExecutorResolver noLockExecutorResolver = services.GetRequiredService <IInternalRequestExecutorResolver>(); IRequestExecutor executor = await noLockExecutorResolver .GetRequestExecutorNoLockAsync(schemaName, cancellationToken) .ConfigureAwait(false); var autoProxy = AutoUpdateRequestExecutorProxy.Create( new RequestExecutorProxy( services.GetRequiredService <IRequestExecutorResolver>(), schemaName), executor); schemaBuilder .AddRemoteExecutor(schemaName, autoProxy) .TryAddSchemaInterceptor <StitchingSchemaInterceptor>() .TryAddTypeInterceptor <StitchingTypeInterceptor>(); }); // Last but not least, we will setup the stitching context which will // provide access to the remote executors which in turn use the just configured // request executor proxies to send requests to the downstream services. builder.Services.TryAddScoped <IStitchingContext, StitchingContext>(); if (ignoreRootTypes) { builder.AddDocumentRewriter(new RemoveRootTypeRewriter(schemaName)); } return(builder); }
public async Task Handle_Subscription_DataReceived_And_Completed() { // arrange var errorHandler = new Mock <IErrorHandler>(); IServiceProvider services = new ServiceCollection() .AddGraphQL() .AddStarWarsTypes() .AddStarWarsRepositories() .AddInMemorySubscriptions() .Services .BuildServiceProvider(); IRequestExecutor executor = await services .GetRequiredService <IRequestExecutorResolver>() .GetRequestExecutorAsync(); var interceptor = new SocketSessionInterceptorMock(); var connection = new SocketConnectionMock { RequestServices = services }; DocumentNode query = Utf8GraphQLParser.Parse( "subscription { onReview(episode: NEW_HOPE) { stars } }"); var handler = new DataStartMessageHandler( executor, interceptor, errorHandler.Object, new NoopExecutionDiagnosticEvents()); 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); var stream = (IResponseStream)await executor.ExecuteAsync( "subscription { onReview(episode: NEW_HOPE) { stars } }"); await executor.ExecuteAsync(@" mutation { createReview(episode:NEW_HOPE review: { commentary: ""foo"" stars: 5 }) { stars } }"); using var cts = new CancellationTokenSource(15000); ConfiguredCancelableAsyncEnumerable <IQueryResult> .Enumerator enumerator = stream.ReadResultsAsync().WithCancellation(cts.Token).GetAsyncEnumerator(); Assert.True(await enumerator.MoveNextAsync()); await Task.Delay(2000, cts.Token); Assert.Collection(connection.SentMessages, t => { Assert.True(t.SequenceEqual( new DataResultMessage(message.Id, enumerator.Current).Serialize())); }); }
public Authenticator(IRequestExecutor requestExecutor, Settings settings) { this.requestExecutor = new RequestExecutionAdapter(requestExecutor); this.settings = settings; }
public BasketController(IRequestExecutor requestExecutor, ISafeRunner safeRunner, IBasketService basketService) { _requestExecutor = requestExecutor; _safeRunner = safeRunner; _basketService = basketService; }
private async Task HandleRequestAsync( HttpContext context, AllowedContentType contentType) { // first we need to get the request executor to be able to execute requests. IRequestExecutor requestExecutor = await GetExecutorAsync(context.RequestAborted); IHttpRequestInterceptor requestInterceptor = requestExecutor.GetRequestInterceptor(); IErrorHandler errorHandler = requestExecutor.GetErrorHandler(); HttpStatusCode? statusCode = null; IExecutionResult?result; try { // next we parse the GraphQL request. IReadOnlyList <GraphQLRequest> requests = await _requestParser.ReadJsonRequestAsync( context.Request.Body, context.RequestAborted); switch (requests.Count) { // if the HTTP request body contains no GraphQL request structure the // whole request is invalid and we will create a GraphQL error response. case 0: { statusCode = HttpStatusCode.BadRequest; IError error = errorHandler.Handle(ErrorHelper.RequestHasNoElements()); result = QueryResultBuilder.CreateError(error); break; } // if the HTTP request body contains a single GraphQL request and we do have // the batch operations query parameter specified we need to execute an // operation batch. // // An operation batch consists of a single GraphQL request document that // contains multiple operations. The batch operation query parameter // defines the order in which the operations shall be executed. case 1 when context.Request.Query.ContainsKey(_batchOperations): { string operationNames = context.Request.Query[_batchOperations]; if (TryParseOperations(operationNames, out IReadOnlyList <string>?ops)) { result = await ExecuteOperationBatchAsync( context, requestExecutor, requestInterceptor, requests[0], ops); } else { IError error = errorHandler.Handle(ErrorHelper.InvalidRequest()); statusCode = HttpStatusCode.BadRequest; result = QueryResultBuilder.CreateError(error); } break; } // if the HTTP request body contains a single GraphQL request and // no batch query parameter is specified we need to execute a single // GraphQL request. // // Most GraphQL requests will be of this type where we want to execute // a single GraphQL query or mutation. case 1: { result = await ExecuteSingleAsync( context, requestExecutor, requestInterceptor, requests[0]); break; } // if the HTTP request body contains more than one GraphQL request than // we need to execute a request batch where we need to execute multiple // fully specified GraphQL requests at once. default: result = await ExecuteBatchAsync( context, requestExecutor, requestInterceptor, requests); break; } } catch (GraphQLRequestException ex) { // A GraphQL request exception is thrown if the HTTP request body couldn't be // parsed. In this case we will return HTTP status code 400 and return a // GraphQL error result. statusCode = HttpStatusCode.BadRequest; result = QueryResultBuilder.CreateError(errorHandler.Handle(ex.Errors)); } catch (Exception ex) { statusCode = HttpStatusCode.InternalServerError; IError error = errorHandler.CreateUnexpectedError(ex).Build(); result = QueryResultBuilder.CreateError(error); } // in any case we will have a valid GraphQL result at this point that can be written // to the HTTP response stream. Debug.Assert(result is not null, "No GraphQL result was created."); await WriteResultAsync(context.Response, result, statusCode, context.RequestAborted); }
public void ExecutorCreated(string name, IRequestExecutor executor) { }
public ChatClient(IRequestExecutor requestExecutor) { _requestExecutor = requestExecutor; }
public HomeController(IRequestExecutor executor) { _requestExecutor = executor; _bikeRequestBuilder = new BikeRequestBuilder(); _itemsPerPage = 6; }
public async Task Create_Touches_Query() { // arrange IRequestExecutor tester = await CreateSchemaAsync <Foo, FooFilterType>(_fooEntities); // act // assert IExecutionResult res1 = await tester.ExecuteAsync( QueryRequestBuilder.New() .SetQuery( @"{ root(where: { bar: { touches: { geometry: { type: Polygon, coordinates: [ [ [240 80], [140 120], [180 240], [280 200], [240 80] ] ] } } } }){ id } }") .Create()); res1.MatchSqlSnapshot("true"); IExecutionResult res2 = await tester.ExecuteAsync( QueryRequestBuilder.New() .SetQuery( @"{ root(where: { bar: { ntouches: { geometry: { type: Polygon, coordinates: [ [ [240 80], [140 120], [180 240], [280 200], [240 80] ] ] } } } }){ id } }") .Create()); res2.MatchSqlSnapshot("false"); }
public void ExecutorEvicted(string name, IRequestExecutor executor) { }
protected ARequest(string baseUrl, IRequestExecutor executor) { this.State = RequestStates.Created; this._myExecutor = executor; this._SetBaseUrl(baseUrl); }
public async Task Array_Filter_On_Scalar_Types() { // arrange IServiceProvider services = new ServiceCollection() .AddSingleton <IMongoCollection <Foo> >(sp => { IMongoDatabase database = _mongoResource.CreateDatabase(); return(database.GetCollection <Foo>("col")); }) .AddGraphQL() .AddQueryType <QueryType>() .BindRuntimeType <ObjectId, IdType>() .Services .BuildServiceProvider(); IRequestExecutor executor = await services.GetRequiredService <IRequestExecutorResolver>() .GetRequestExecutorAsync(); IMongoCollection <Foo> collection = services.GetRequiredService <IMongoCollection <Foo> >(); await collection.InsertOneAsync(new Foo { BarCollection = new List <string> { "a", "b", "c" }, BazCollection = new List <Baz> { new Baz { Quux = "a" }, new Baz { Quux = "b" } }, Bars = new[] { "d", "e", "f" }, Bazs = new[] { new Baz { Quux = "c" }, new Baz { Quux = "d" } }, Quux = "abc" }); ISchema schema = SchemaBuilder.New() .AddQueryType <QueryType>() .AddServices(services) .BindClrType <ObjectId, IdType>() .Create(); IReadOnlyQueryRequest request = QueryRequestBuilder.New() .SetQuery( "{" + "foos(where: { bars_some: { element: \"e\" } }) { bars } " + "}") .Create(); // act IExecutionResult result = await executor.ExecuteAsync(request); // assert result.MatchSnapshot(); }
public async Task Create_Overlaps_Query() { // arrange IRequestExecutor tester = await CreateSchemaAsync <Foo, FooFilterType>(_fooEntities); // act // assert IExecutionResult res1 = await tester.ExecuteAsync( QueryRequestBuilder.New() .SetQuery( @"{ root(where: { bar: { overlaps: { geometry: { type: Polygon, coordinates: [ [150 150], [270 150], [330 150], [250 70], [190 70], [70 70], [150 150] ] } } } }){ id } }") .Create()); res1.MatchSqlSnapshot("true"); IExecutionResult res2 = await tester.ExecuteAsync( QueryRequestBuilder.New() .SetQuery( @"{ root(where: { bar: { noverlaps: { geometry: { type: Polygon, coordinates: [ [150 150], [270 150], [330 150], [250 70], [190 70], [70 70], [150 150] ] } } } }){ id } }") .Create()); res2.MatchSqlSnapshot("false"); }
public async Task AutoMerge_HotReload_Schema() { // arrange NameString configurationName = "C" + Guid.NewGuid().ToString("N"); var schemaDefinitionV2 = FileResource.Open("AccountSchemaDefinition.json"); IHttpClientFactory httpClientFactory = CreateDefaultRemoteSchemas(configurationName); IDatabase database = _connection.GetDatabase(); for (var i = 0; i < 10; i++) { if (await database.SetLengthAsync(configurationName.Value) == 4) { break; } await Task.Delay(150); } IRequestExecutorResolver executorResolver = new ServiceCollection() .AddSingleton(httpClientFactory) .AddGraphQL() .AddQueryType(d => d.Name("Query")) .AddRemoteSchemasFromRedis(configurationName, s => _connection) .Services .BuildServiceProvider() .GetRequiredService <IRequestExecutorResolver>(); await executorResolver.GetRequestExecutorAsync(); var raised = false; executorResolver.RequestExecutorEvicted += (sender, args) => { if (args.Name.Equals(Schema.DefaultName)) { raised = true; } }; // act Assert.False(raised, "eviction was raised before act."); await database.StringSetAsync($"{configurationName}.{_accounts}", schemaDefinitionV2); await _connection.GetSubscriber().PublishAsync(configurationName.Value, _accounts); for (var i = 0; i < 10; i++) { if (raised) { break; } await Task.Delay(150); } // assert Assert.True(raised, "schema evicted."); IRequestExecutor executor = await executorResolver.GetRequestExecutorAsync(); ObjectType type = executor.Schema.GetType <ObjectType>("User"); Assert.True(type.Fields.ContainsField("foo"), "foo field exists."); }
public RequestExecutorEvictedEventArgs(string name, IRequestExecutor evictedExecutor) { Name = name; EvictedExecutor = evictedExecutor; }
public Authenticator(IRequestExecutor requestExecutor) : this(requestExecutor, new Settings()) { }
public async Task ExecuteExportObjectList() { // arrange Snapshot.FullName(); IRequestExecutor executor = await CreateExecutorAsync(c => c .AddDocumentFromString( @" type Query { foo(f: [FooInput]) : [Foo] } type Foo { bar: String! } input FooInput { bar: String! }") .AddResolver("Query", "foo", ctx => { List <object> list = ctx.ArgumentValue <List <object> >("f"); if (list is null) { return(new List <object> { new Dictionary <string, object> { { "bar", "123" } } }); } list.Add(new Dictionary <string, object> { { "bar", "456" } }); return(list); }) .UseField(next => context => { var o = context.Parent <object>(); if (o is Dictionary <string, object> d && d.TryGetValue(context.ResponseName, out var v)) { context.Result = v; } return(next(context)); }) .AddExportDirectiveType()); // act var batch = new List <IReadOnlyQueryRequest> { QueryRequestBuilder.New() .SetQuery( @"{ foo @export(as: ""b"") { bar } }") .Create(), QueryRequestBuilder.New() .SetQuery( @"{ foo(f: $b) { bar } }") .Create() }; IBatchQueryResult batchResult = await executor.ExecuteBatchAsync(batch); // assert await batchResult.ToJsonAsync().MatchSnapshotAsync(); }
public async Task AutoMerge_Execute_Variables() { // arrange IHttpClientFactory httpClientFactory = Context.CreateDefaultRemoteSchemas(); IRequestExecutor executor = await new ServiceCollection() .AddSingleton(httpClientFactory) .AddGraphQL() .AddRemoteSchema(Context.ContractSchema) .AddRemoteSchema(Context.CustomerSchema) .AddTypeExtensionsFromString( @"extend type Customer { contracts: [Contract!] @delegate( schema: ""contract"", path: ""contracts(customerId:$fields:id)"") }") .ModifyRequestOptions(o => o.IncludeExceptionDetails = true) .BuildRequestExecutorAsync(); var variables = new Dictionary <string, object> { { "customerId", "Q3VzdG9tZXIKZDE=" }, { "deep", "deep" }, { "deeper", "deeper" } }; // act IExecutionResult result = await executor.ExecuteAsync( @"query customer_query( $customerId: ID! $deep: String! $deeper: String! $deeperArray: String $complex: ComplexInputType $deeperInArray: String ) { customer(id: $customerId) { name consultant { name } complexArg( arg: { value: $deep deeper: { value: ""CONSTANT"" deeper: { value: $deeper deeperArray: [ { value: ""CONSTANT_ARRAY"", deeper: { value: $deeperInArray } } ] } } deeperArray: [ { value: ""CONSTANT_ARRAY"", deeper: { value: $deeperArray } } $complex ] } ) contracts { id ... on LifeInsuranceContract { premium } ... on SomeOtherContract { expiryDate } } } }", variables); // assert result.MatchSnapshot(); }
public async Task GetItems_ObjectEqualsFilter_FirstItems_Is_Returned() { // arrange var serviceCollection = new ServiceCollection(); IServiceProvider services = new ServiceCollection() .AddSingleton <IMongoCollection <Model> >(sp => { IMongoDatabase database = _mongoResource.CreateDatabase(); IMongoCollection <Model> collection = database.GetCollection <Model>("col"); collection.InsertMany(new[] { new Model { Nested = null }, new Model { Nested = new Model { Nested = new Model { Foo = "abc", Bar = 1, Baz = true } } }, new Model { Nested = new Model { Nested = new Model { Foo = "def", Bar = 2, Baz = false } } }, }); return(collection); }) .AddGraphQL() .AddQueryType <QueryType>() .Services .BuildServiceProvider(); IRequestExecutor executor = await services.GetRequiredService <IRequestExecutorResolver>() .GetRequestExecutorAsync(); IReadOnlyQueryRequest request = QueryRequestBuilder.New() .SetQuery( "{ items(where: { nested:{ nested: { foo: \"abc\" " + "} } }) { nested { nested { foo } } } }") .Create(); // act IExecutionResult result = await executor.ExecuteAsync(request); // assert result.MatchSnapshot(); }
public static IRequestExecutorBuilder AddRemoteSchema( this IRequestExecutorBuilder builder, NameString schemaName, Func <IServiceProvider, CancellationToken, ValueTask <RemoteSchemaDefinition> > loadSchema, bool ignoreRootTypes = false) { if (builder is null) { throw new ArgumentNullException(nameof(builder)); } if (loadSchema is null) { throw new ArgumentNullException(nameof(loadSchema)); } schemaName.EnsureNotEmpty(nameof(schemaName)); // first we add a full GraphQL schema and executor that represents the remote schema. // This remote schema will be used by the stitching engine to execute queries against // this schema and also to lookup types in order correctly convert between scalars. builder .AddGraphQL(schemaName) .ConfigureSchemaServices(services => { services.TryAddSingleton( sp => new HttpRequestClient( sp.GetApplicationService <IHttpClientFactory>(), sp.GetRequiredService <IErrorHandler>(), sp.GetRequiredService <IHttpStitchingRequestInterceptor>())); services.TryAddSingleton < IHttpStitchingRequestInterceptor, HttpStitchingRequestInterceptor>(); }) .ConfigureSchemaAsync( async(services, schemaBuilder, cancellationToken) => { // No we need to load the schema document. RemoteSchemaDefinition schemaDef = await loadSchema(services, cancellationToken) .ConfigureAwait(false); DocumentNode document = schemaDef.Document.RemoveBuiltInTypes(); // We store the schema definition on the schema building context // and copy it to the schema once that is built. schemaBuilder .SetContextData(typeof(RemoteSchemaDefinition).FullName !, schemaDef) .TryAddTypeInterceptor <CopySchemaDefinitionTypeInterceptor>(); // The document is used to create a SDL-first schema ... schemaBuilder.AddDocument(document); // ... which will fail if any resolver is actually used ... schemaBuilder.Use(next => context => throw new NotSupportedException()); }) // ... instead we are using a special request pipeline that does everything like // the standard pipeline except the last middleware will not start the execution // algorithms but delegate the request via HTTP to the downstream schema. .UseHttpRequestPipeline(); // Next, we will register a request executor proxy with the stitched schema, // that the stitching runtime will use to send requests to the schema representing // the downstream service. builder .ConfigureSchemaAsync(async(services, schemaBuilder, cancellationToken) => { IInternalRequestExecutorResolver noLockExecutorResolver = services.GetRequiredService <IInternalRequestExecutorResolver>(); IRequestExecutor executor = await noLockExecutorResolver .GetRequestExecutorNoLockAsync(schemaName, cancellationToken) .ConfigureAwait(false); var autoProxy = AutoUpdateRequestExecutorProxy.Create( new RequestExecutorProxy( services.GetRequiredService <IRequestExecutorResolver>(), schemaName), executor); schemaBuilder .AddRemoteExecutor(schemaName, autoProxy) .TryAddSchemaInterceptor <StitchingSchemaInterceptor>() .TryAddTypeInterceptor <StitchingTypeInterceptor>(); var schemaDefinition = (RemoteSchemaDefinition)autoProxy.Schema .ContextData[typeof(RemoteSchemaDefinition).FullName !] !; var extensionsRewriter = new SchemaExtensionsRewriter(); foreach (var extensionDocument in schemaDefinition.ExtensionDocuments) { var doc = (DocumentNode)extensionsRewriter .Rewrite(extensionDocument, schemaName.Value); SchemaExtensionNode?schemaExtension = doc.Definitions.OfType <SchemaExtensionNode>().FirstOrDefault(); if (schemaExtension is not null && schemaExtension.Directives.Count == 0 && schemaExtension.OperationTypes.Count == 0) { var definitions = doc.Definitions.ToList(); definitions.Remove(schemaExtension); doc = doc.WithDefinitions(definitions); } schemaBuilder.AddTypeExtensions(doc); } schemaBuilder.AddTypeRewriter( new RemoveFieldRewriter( new FieldReference( autoProxy.Schema.QueryType.Name, SchemaDefinitionFieldNames.SchemaDefinitionField), schemaName)); schemaBuilder.AddDocumentRewriter( new RemoveTypeRewriter( SchemaDefinitionType.Names.SchemaDefinition, schemaName)); foreach (var schemaAction in extensionsRewriter.SchemaActions) { switch (schemaAction.Name.Value) { case DirectiveNames.RemoveRootTypes: schemaBuilder.AddDocumentRewriter( new RemoveRootTypeRewriter(schemaName)); break; case DirectiveNames.RemoveType: schemaBuilder.AddDocumentRewriter( new RemoveTypeRewriter( GetArgumentValue( schemaAction, DirectiveFieldNames.RemoveType_TypeName), schemaName)); break; case DirectiveNames.RenameType: schemaBuilder.AddTypeRewriter( new RenameTypeRewriter( GetArgumentValue( schemaAction, DirectiveFieldNames.RenameType_TypeName), GetArgumentValue( schemaAction, DirectiveFieldNames.RenameType_NewTypeName), schemaName)); break; case DirectiveNames.RenameField: schemaBuilder.AddTypeRewriter( new RenameFieldRewriter( new FieldReference( GetArgumentValue( schemaAction, DirectiveFieldNames.RenameField_TypeName), GetArgumentValue( schemaAction, DirectiveFieldNames.RenameField_FieldName)), GetArgumentValue( schemaAction, DirectiveFieldNames.RenameField_NewFieldName), schemaName)); break; } } });
public async Task Create_ObjectString_OrderBy_TwoProperties() { // arrange IRequestExecutor tester = _cache.CreateSchema <Bar, BarSortType>(_barEntities); // act // assert IExecutionResult res1 = await tester.ExecuteAsync( QueryRequestBuilder.New() .SetQuery( "{ root(order: { foo: { barBool: ASC, barShort: ASC }}) " + "{ foo{ barBool barShort}}}") .Create()); res1.MatchSnapshot("ASC"); IExecutionResult res2 = await tester.ExecuteAsync( QueryRequestBuilder.New() .SetQuery( @" { root(order: [ { foo: { barBool: ASC } }, { foo: { barShort: ASC } }]) { foo { barBool barShort } } } ") .Create()); res2.MatchSnapshot("ASC"); IExecutionResult res3 = await tester.ExecuteAsync( QueryRequestBuilder.New() .SetQuery( "{ root(order: { foo: { barBool: DESC, barShort: DESC}}) " + "{ foo{ barBool barShort}}}") .Create()); res3.MatchSnapshot("DESC"); IExecutionResult res4 = await tester.ExecuteAsync( QueryRequestBuilder.New() .SetQuery( @" { root(order: [ { foo: { barBool: DESC } }, { foo: { barShort: DESC } }]) { foo { barBool barShort } } } ") .Create()); res4.MatchSnapshot("DESC"); }