-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Context to DIObjectGraphBase; use GetOrCreate when creating insta…
…nces (#6)
- Loading branch information
Showing
5 changed files
with
315 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,68 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using GraphQL.Execution; | ||
using GraphQL.Instrumentation; | ||
using GraphQL.Language.AST; | ||
using GraphQL.Types; | ||
|
||
namespace GraphQL.DI | ||
{ | ||
/// <summary> | ||
/// This is a required base type of all DI-created graph types. <see cref="DIObjectGraphBase"/> may be | ||
/// used if the <see cref="IResolveFieldContext.Source"/> type is <see cref="object"/>. | ||
/// </summary> | ||
//this class is a placeholder for future support of properties or methods on the base class | ||
public class DIObjectGraphBase<TSource> : IDIObjectGraphBase<TSource> | ||
public abstract class DIObjectGraphBase<TSource> : IDIObjectGraphBase<TSource>, IResolveFieldContext<TSource> | ||
{ | ||
//this would be an ideal spot to put public readonly fields for the resolving query, such as Schema, Metrics, Executor, and so on, rather than being inside the ResolveFieldContext instance. | ||
//this could only contain fields that are not unique to a resolving field (such as Source), so as to not break multithreading support | ||
//with DI, any objects necessary could be brought in via dependency injection (such as Schema), so they really don't need to be in here | ||
|
||
/// <summary> | ||
/// The <see cref="IResolveFieldContext"/> for the current field. | ||
/// </summary> | ||
public IResolveFieldContext Context { get; private set; } = null!; | ||
|
||
/// <inheritdoc cref="IResolveFieldContext.Source"/> | ||
public TSource Source => (TSource)Context.Source; | ||
|
||
/// <inheritdoc cref="IResolveFieldContext.CancellationToken"/> | ||
public CancellationToken RequestAborted => Context.CancellationToken; | ||
|
||
/// <inheritdoc cref="IProvideUserContext.UserContext"/> | ||
public IDictionary<string, object> UserContext => Context.UserContext; | ||
|
||
/// <inheritdoc cref="IResolveFieldContext.Metrics"/> | ||
public Metrics Metrics => Context.Metrics; | ||
|
||
IResolveFieldContext IDIObjectGraphBase.Context { get => Context; set => Context = value; } | ||
Field IResolveFieldContext.FieldAst => Context.FieldAst; | ||
FieldType IResolveFieldContext.FieldDefinition => Context.FieldDefinition; | ||
IObjectGraphType IResolveFieldContext.ParentType => Context.ParentType; | ||
IResolveFieldContext IResolveFieldContext.Parent => Context.Parent; | ||
IDictionary<string, ArgumentValue> IResolveFieldContext.Arguments => Context.Arguments; | ||
object IResolveFieldContext.RootValue => Context.RootValue; | ||
object IResolveFieldContext.Source => Context.Source; | ||
ISchema IResolveFieldContext.Schema => Context.Schema; | ||
Document IResolveFieldContext.Document => Context.Document; | ||
Operation IResolveFieldContext.Operation => Context.Operation; | ||
Variables IResolveFieldContext.Variables => Context.Variables; | ||
CancellationToken IResolveFieldContext.CancellationToken => Context.CancellationToken; | ||
ExecutionErrors IResolveFieldContext.Errors => Context.Errors; | ||
IEnumerable<object> IResolveFieldContext.Path => Context.Path; | ||
IEnumerable<object> IResolveFieldContext.ResponsePath => Context.ResponsePath; | ||
Dictionary<string, Field> IResolveFieldContext.SubFields => Context.SubFields; | ||
IDictionary<string, object> IResolveFieldContext.Extensions => Context.Extensions; | ||
IServiceProvider IResolveFieldContext.RequestServices => Context.RequestServices; | ||
IExecutionArrayPool IResolveFieldContext.ArrayPool => Context.ArrayPool; | ||
} | ||
|
||
/// <summary> | ||
/// This is a required base type of all DI-created graph types. <see cref="DIObjectGraphBase{TSource}"/> may be | ||
/// used when the <see cref="IResolveFieldContext.Source"/> type is not <see cref="object"/>. | ||
/// </summary> | ||
public class DIObjectGraphBase : DIObjectGraphBase<object>, IDIObjectGraphBase<object> | ||
public abstract class DIObjectGraphBase : DIObjectGraphBase<object>, IDIObjectGraphBase<object> | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
using System.Threading; | ||
using GraphQL; | ||
using GraphQL.DI; | ||
using GraphQL.Execution; | ||
using GraphQL.Instrumentation; | ||
using GraphQL.Language.AST; | ||
using GraphQL.Types; | ||
using Moq; | ||
using Shouldly; | ||
using Xunit; | ||
|
||
namespace Tests | ||
{ | ||
public class DIObjectGraphBaseTests | ||
{ | ||
private readonly DIObjectGraphBase _graph = new CTest(); | ||
private IResolveFieldContext _graphContext => (IResolveFieldContext)_graph; | ||
private readonly Mock<IResolveFieldContext> _mockContext = new Mock<IResolveFieldContext>(MockBehavior.Strict); | ||
private IResolveFieldContext _context => _mockContext.Object; | ||
|
||
public DIObjectGraphBaseTests() | ||
{ | ||
((IDIObjectGraphBase)_graph).Context = _context; | ||
((IDIObjectGraphBase)_graph).Context.ShouldBe(_context); | ||
} | ||
|
||
[Fact] | ||
public void Context() | ||
{ | ||
_graph.Context.ShouldBe(_context); | ||
} | ||
|
||
[Fact] | ||
public void RequestAborted() | ||
{ | ||
var token = new CancellationTokenSource().Token; | ||
_mockContext.Setup(x => x.CancellationToken).Returns(token); | ||
_graph.RequestAborted.ShouldBe(token); | ||
} | ||
|
||
[Fact] | ||
public void Metrics() | ||
{ | ||
var metrics = new Metrics(); | ||
_mockContext.Setup(x => x.Metrics).Returns(metrics); | ||
_graph.Metrics.ShouldBe(metrics); | ||
} | ||
|
||
[Fact] | ||
public void UserContext() | ||
{ | ||
var userContext = new Dictionary<string, object>(); | ||
_mockContext.Setup(x => x.UserContext).Returns(userContext); | ||
_graph.UserContext.ShouldBe(userContext); | ||
} | ||
|
||
[Fact] | ||
public void Source() | ||
{ | ||
var source = new object(); | ||
_mockContext.Setup(x => x.Source).Returns(source); | ||
_graph.Source.ShouldBe(source); | ||
} | ||
|
||
[Fact] | ||
public void SourceTyped() | ||
{ | ||
_mockContext.Setup(x => x.Source).Returns(3); | ||
var graph = new CTest<int>(); | ||
((IDIObjectGraphBase)graph).Context = _context; | ||
graph.Source.ShouldBe(3); | ||
} | ||
|
||
[Fact] | ||
public void RFC_FieldAst() | ||
{ | ||
var fieldAst = new Field(default, default); | ||
_mockContext.Setup(x => x.FieldAst).Returns(fieldAst); | ||
_graphContext.FieldAst.ShouldBe(fieldAst); | ||
} | ||
|
||
[Fact] | ||
public void RFC_FieldDefinition() | ||
{ | ||
var fieldDef = new FieldType(); | ||
_mockContext.Setup(x => x.FieldDefinition).Returns(fieldDef); | ||
_graphContext.FieldDefinition.ShouldBe(fieldDef); | ||
} | ||
|
||
[Fact] | ||
public void RFC_ParentType() | ||
{ | ||
var obj = Mock.Of<IObjectGraphType>(); | ||
_mockContext.Setup(x => x.ParentType).Returns(obj); | ||
_graphContext.ParentType.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_Parent() | ||
{ | ||
var obj = Mock.Of<IResolveFieldContext>(); | ||
_mockContext.Setup(x => x.Parent).Returns(obj); | ||
_graphContext.Parent.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_Arguments() | ||
{ | ||
var obj = Mock.Of<IDictionary<string, ArgumentValue>>(); | ||
_mockContext.Setup(x => x.Arguments).Returns(obj); | ||
_graphContext.Arguments.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_RootValue() | ||
{ | ||
var obj = new object(); | ||
_mockContext.Setup(x => x.RootValue).Returns(obj); | ||
_graphContext.RootValue.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_Source() | ||
{ | ||
var obj = new object(); | ||
_mockContext.Setup(x => x.Source).Returns(obj); | ||
_graphContext.Source.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_Schema() | ||
{ | ||
var obj = Mock.Of<ISchema>(); | ||
_mockContext.Setup(x => x.Schema).Returns(obj); | ||
_graphContext.Schema.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_Document() | ||
{ | ||
var obj = new Document(); | ||
_mockContext.Setup(x => x.Document).Returns(obj); | ||
_graphContext.Document.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_Operation() | ||
{ | ||
var obj = new Operation(default); | ||
_mockContext.Setup(x => x.Operation).Returns(obj); | ||
_graphContext.Operation.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_Variables() | ||
{ | ||
var obj = new Variables(); | ||
_mockContext.Setup(x => x.Variables).Returns(obj); | ||
_graphContext.Variables.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_CancellationToken() | ||
{ | ||
var obj = new CancellationTokenSource().Token; | ||
_mockContext.Setup(x => x.CancellationToken).Returns(obj); | ||
_graphContext.CancellationToken.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_Errors() | ||
{ | ||
var obj = new ExecutionErrors(); | ||
_mockContext.Setup(x => x.Errors).Returns(obj); | ||
_graphContext.Errors.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_Path() | ||
{ | ||
var obj = Mock.Of<IEnumerable<object>>(); | ||
_mockContext.Setup(x => x.Path).Returns(obj); | ||
Assert.StrictEqual(_graphContext.Path, obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_ResponsePath() | ||
{ | ||
var obj = Mock.Of<IEnumerable<object>>(); | ||
_mockContext.Setup(x => x.ResponsePath).Returns(obj); | ||
Assert.StrictEqual(_graphContext.ResponsePath, obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_SubFields() | ||
{ | ||
var obj = new Dictionary<string, Field>(); | ||
_mockContext.Setup(x => x.SubFields).Returns(obj); | ||
_graphContext.SubFields.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_Extensions() | ||
{ | ||
var obj = Mock.Of<IDictionary<string, object>>(); | ||
_mockContext.Setup(x => x.Extensions).Returns(obj); | ||
_graphContext.Extensions.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_RequestServices() | ||
{ | ||
var obj = Mock.Of<IServiceProvider>(); | ||
_mockContext.Setup(x => x.RequestServices).Returns(obj); | ||
_graphContext.RequestServices.ShouldBe(obj); | ||
} | ||
|
||
[Fact] | ||
public void RFC_ArrayPool() | ||
{ | ||
var obj = Mock.Of<IExecutionArrayPool>(); | ||
_mockContext.Setup(x => x.ArrayPool).Returns(obj); | ||
_graphContext.ArrayPool.ShouldBe(obj); | ||
} | ||
|
||
private class CTest : DIObjectGraphBase | ||
{ | ||
} | ||
|
||
private class CTest<T> : DIObjectGraphBase<T> | ||
{ | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters