Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data Loaders #189

Merged
merged 25 commits into from
Jul 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,8 @@ Moreover, we are working on the following parts that are not defined in the spec

### Execution Engine

- [ ] Custom Context Objects
- [ ] Data Loader Integration / Batched Operations
- [x] Custom Context Objects
- [x] Data Loader Integration / Batched Operations

### Schema Creation

Expand Down
1 change: 1 addition & 0 deletions run-tests.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
dotnet build src
dotnet test src/Runtime.Tests
dotnet test src/Language.Tests
dotnet test src/Core.Tests
dotnet test src/AspNetCore.Tests
1 change: 1 addition & 0 deletions run-tests.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
dotnet build src
dotnet test src/Runtime.Tests
dotnet test src/Language.Tests --no-build
dotnet test src/Core.Tests --no-build
dotnet test src/AspNetCore.Tests --no-build
10 changes: 10 additions & 0 deletions src/Abstractions/DataLoaderAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace HotChocolate
{
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class DataLoaderAttribute
: Attribute
{
}
}
17 changes: 17 additions & 0 deletions src/Abstractions/IResolverResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace HotChocolate
{
public interface IResolverResult
{
string ErrorMessage { get; }

bool IsError { get; }

object Value { get; }
}

public interface IResolverResult<out TValue>
: IResolverResult
{
new TValue Value { get; }
}
}
31 changes: 31 additions & 0 deletions src/Abstractions/ResolverResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;

namespace HotChocolate
{
public readonly struct ResolverResult<TValue>
: IResolverResult<TValue>
{
public ResolverResult(string errorMessage)
{
Value = default;
ErrorMessage = errorMessage
?? throw new ArgumentNullException(nameof(errorMessage));
IsError = true;
}

public ResolverResult(TValue value)
{
Value = default;
ErrorMessage = null;
IsError = false;
}

public TValue Value { get; }

public string ErrorMessage { get; }

public bool IsError { get; }

object IResolverResult.Value => Value;
}
}
2 changes: 2 additions & 0 deletions src/AspNetCore.Tests/QueryMiddlewareTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ public async Task HttpPost_WithHttpContext()
Query = @"
{
requestPath
requestPath2
requestPath3
}"
};

Expand Down
11 changes: 11 additions & 0 deletions src/AspNetCore.Tests/Schema/Query.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using HotChocolate.Resolvers;
using Microsoft.AspNetCore.Http;

namespace HotChocolate.AspNetCore
Expand Down Expand Up @@ -26,6 +27,16 @@ public string GetRequestPath()
return _context.Request.Path;
}

public string GetRequestPath2(IResolverContext context)
{
return context.Service<HttpContext>().Request.Path;
}

public string GetRequestPath3([Service]HttpContext context)
{
return context.Request.Path;
}

public Foo GetBasic()
{
return new Foo
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"Data": {
"requestPath": "/"
"requestPath": "/",
"requestPath2": "/",
"requestPath3": "/"
},
"Errors": null
}
4 changes: 2 additions & 2 deletions src/Core.Tests/Execution/ArgumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public async Task ListOfFoo()

// act
IExecutionResult result = await schema.ExecuteAsync(
"query x($x:[Foo]) { a(foo:$x) { foo } }",
"query x($x:[FooInput]) { a(foo:$x) { foo } }",
new Dictionary<string, IValueNode> { { "x", list } });

// assert
Expand Down Expand Up @@ -140,7 +140,7 @@ public async Task SingleFoo()

// act
IExecutionResult result = await schema.ExecuteAsync(
"query x($x:Foo) { a(foo:$x) { foo } }",
"query x($x:FooInput) { a(foo:$x) { foo } }",
new Dictionary<string, IValueNode> { { "x", obj } });

// assert
Expand Down
1 change: 1 addition & 0 deletions src/Core.Tests/Execution/OperationExecuterErrorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ private Schema CreateSchema()

return Schema.Create(c =>
{
c.Options.ExecutionTimeout = TimeSpan.FromSeconds(30);
c.Options.StrictValidation = true;
c.RegisterQueryType<QueryType>();
});
Expand Down
22 changes: 10 additions & 12 deletions src/Core.Tests/Execution/OperationRequestTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Threading.Tasks;
using HotChocolate.Language;
using HotChocolate.Runtime;
using Moq;
using Xunit;

namespace HotChocolate.Execution
Expand All @@ -15,11 +16,9 @@ public async Task ResolveSimpleOneLevelQuery()
{
// arrange
Schema schema = CreateSchema();
var dataLoaderDescriptors =
new DataLoaderDescriptorCollection(schema.DataLoaders);
var dataLoaderState = new DataLoaderState(
schema.Services, dataLoaderDescriptors,
Enumerable.Empty<StateObjectCollection<string>>());
var session = new Mock<ISession>(MockBehavior.Strict);
session.Setup(t => t.DataLoaders).Returns((IDataLoaderProvider)null);
session.Setup(t => t.CustomContexts).Returns((ICustomContextProvider)null);
DocumentNode query = Parser.Default.Parse(@"
{
a
Expand All @@ -31,7 +30,7 @@ public async Task ResolveSimpleOneLevelQuery()
OperationExecuter operationExecuter =
new OperationExecuter(schema, query, operation);
IExecutionResult result = await operationExecuter.ExecuteAsync(
new OperationRequest(schema.Services, dataLoaderState),
new OperationRequest(schema.Services, session.Object),
CancellationToken.None);

// assert
Expand Down Expand Up @@ -60,11 +59,10 @@ public async Task ExecuteMutationSerially()
cnf.BindResolver(ctx => state = ctx.Argument<int>("newNumber"))
.To("Mutation", "changeTheNumber");
});
var dataLoaderDescriptors =
new DataLoaderDescriptorCollection(schema.DataLoaders);
var dataLoaderState = new DataLoaderState(
schema.Services, dataLoaderDescriptors,
Enumerable.Empty<StateObjectCollection<string>>());

var session = new Mock<ISession>(MockBehavior.Strict);
session.Setup(t => t.DataLoaders).Returns((IDataLoaderProvider)null);
session.Setup(t => t.CustomContexts).Returns((ICustomContextProvider)null);

DocumentNode query = Parser.Default.Parse(
FileResource.Open("MutationExecutionQuery.graphql"));
Expand All @@ -75,7 +73,7 @@ public async Task ExecuteMutationSerially()
OperationExecuter operationExecuter =
new OperationExecuter(schema, query, operation);
IExecutionResult result = await operationExecuter.ExecuteAsync(
new OperationRequest(schema.Services, dataLoaderState),
new OperationRequest(schema.Services, session.Object),
CancellationToken.None);

// assert
Expand Down
77 changes: 77 additions & 0 deletions src/Core.Tests/Integration/DataLoader/CustomContextTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using HotChocolate.Execution;
using HotChocolate.Runtime;
using Xunit;

namespace HotChocolate.Integration.DataLoader
{
public class CustomContextTests
{
[Fact]
public async Task RequestCustomContext()
{
// arrange
ISchema schema = CreateSchema(ExecutionScope.Request);
QueryExecuter executer = new QueryExecuter(schema, 10);

// act
List<IExecutionResult> results = new List<IExecutionResult>();
results.Add(await executer.ExecuteAsync(
new QueryRequest("{ a: a b: a }")));
results.Add(await executer.ExecuteAsync(
new QueryRequest("{ a: a b: a }")));
results.Add(await executer.ExecuteAsync(
new QueryRequest("{ a: a b: a }")));
results.Add(await executer.ExecuteAsync(
new QueryRequest("{ a: a b: a }")));

// assert
Assert.Collection(results,
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors));
Assert.Equal(Snapshot.Current(), Snapshot.New(results));
}

[Fact]
public async Task GlobalCustomContext()
{
// arrange
ISchema schema = CreateSchema(ExecutionScope.Global);
QueryExecuter executer = new QueryExecuter(schema, 10);

// act
List<IExecutionResult> results = new List<IExecutionResult>();
results.Add(await executer.ExecuteAsync(new QueryRequest("{ a }")));
results.Add(await executer.ExecuteAsync(new QueryRequest("{ a }")));
results.Add(await executer.ExecuteAsync(new QueryRequest("{ a }")));
results.Add(await executer.ExecuteAsync(new QueryRequest("{ a }")));

// assert
Assert.Collection(results,
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors));
Assert.Equal(Snapshot.Current(), Snapshot.New(results));
}

private static ISchema CreateSchema(ExecutionScope scope)
{
return Schema.Create("type Query { a: String }", c =>
{
c.Options.ExecutionTimeout = TimeSpan.FromSeconds(30);
c.RegisterCustomContext<MyCustomContext>(scope);
c.BindResolver(ctx =>
{
MyCustomContext cctx = ctx.CustomContext<MyCustomContext>();
cctx.Count = cctx.Count + 1;
return cctx.Count.ToString();
}).To("Query", "a");
});
}
}
}
90 changes: 90 additions & 0 deletions src/Core.Tests/Integration/DataLoader/DataLoaderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using HotChocolate.Execution;
using HotChocolate.Runtime;
using Xunit;

namespace HotChocolate.Integration.DataLoader
{
public class DataLoaderTests
{
[Fact]
public async Task RequestDataLoader()
{
// arrange
ISchema schema = CreateSchema(ExecutionScope.Request);
QueryExecuter executer = new QueryExecuter(schema, 10);

// act
List<IExecutionResult> results = new List<IExecutionResult>();
results.Add(await executer.ExecuteAsync(new QueryRequest(
@"{
a: withDataLoader(key: ""a"")
b: withDataLoader(key: ""b"")
}")));
results.Add(await executer.ExecuteAsync(new QueryRequest(
@"{
a: withDataLoader(key: ""a"")
}")));
results.Add(await executer.ExecuteAsync(new QueryRequest(
@"{
c: withDataLoader(key: ""c"")
}")));
results.Add(await executer.ExecuteAsync(new QueryRequest(
"{ loads }")));

// assert
Assert.Collection(results,
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors));
Assert.Equal(Snapshot.Current(), Snapshot.New(results));
}

[Fact]
public async Task GlobalDataLoader()
{
// arrange
ISchema schema = CreateSchema(ExecutionScope.Global);
QueryExecuter executer = new QueryExecuter(schema, 10);

// act
List<IExecutionResult> results = new List<IExecutionResult>();
results.Add(await executer.ExecuteAsync(new QueryRequest(
@"{
a: withDataLoader(key: ""a"")
b: withDataLoader(key: ""b"")
}")));
results.Add(await executer.ExecuteAsync(new QueryRequest(
@"{
a: withDataLoader(key: ""a"")
}")));
results.Add(await executer.ExecuteAsync(new QueryRequest(
@"{
c: withDataLoader(key: ""c"")
}")));
results.Add(await executer.ExecuteAsync(new QueryRequest(
"{ loads }")));

// assert
Assert.Collection(results,
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors),
t => Assert.Null(t.Errors));
Assert.Equal(Snapshot.Current(), Snapshot.New(results));
}

private static ISchema CreateSchema(ExecutionScope scope)
{
return Schema.Create(c =>
{
c.Options.ExecutionTimeout = TimeSpan.FromSeconds(30);
c.RegisterDataLoader<TestDataLoader>(scope);
c.RegisterQueryType<Query>();
});
}
}
}
7 changes: 7 additions & 0 deletions src/Core.Tests/Integration/DataLoader/MyCustomContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace HotChocolate.Integration.DataLoader
{
public class MyCustomContext
{
public int Count { get; set; }
}
}
Loading