diff --git a/global.json b/global.json index 79422f0cc1c..c685cffc7ac 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "3.0.100" + "version": "3.1.101" } } diff --git a/src/Core/Abstractions/ParentAttribute.cs b/src/Core/Abstractions/ParentAttribute.cs index f7b9a857298..19085f48c01 100644 --- a/src/Core/Abstractions/ParentAttribute.cs +++ b/src/Core/Abstractions/ParentAttribute.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace HotChocolate { diff --git a/src/Core/Core.sln b/src/Core/Core.sln index 9e90018dc7b..c0a263f2a65 100644 --- a/src/Core/Core.sln +++ b/src/Core/Core.sln @@ -67,6 +67,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Tests", "Type EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Mongo.Tests", "Types.Sorting.Mongo.Tests\Types.Sorting.Mongo.Tests.csproj", "{E8843255-77EB-471F-B682-528BB4B5D1D5}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection", "Types.Selection\Types.Selection.csproj", "{0FD6B6D1-00AB-42CF-800F-4039A976A75A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.Abstractions.Tests", "Types.Selection.Abstractions.Tests\Types.Selection.Abstractions.Tests.csproj", "{726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.InMemory.Tests", "Types.Selection.InMemory.Tests\Types.Selection.InMemory.Tests.csproj", "{3DB2E3F5-0DBE-4B91-A335-D82F8794324B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.Mongo.Tests", "Types.Selection.Mongo.Tests\Types.Selection.Mongo.Tests.csproj", "{21AA751A-4C29-414C-B476-EE9204A48DDD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.SqlServer.Tests", "Types.Selection.SqlServer.Tests\Types.Selection.SqlServer.Tests.csproj", "{07674D84-4A5C-4608-BECE-03630D38275F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -449,6 +459,66 @@ Global {E8843255-77EB-471F-B682-528BB4B5D1D5}.Release|x64.Build.0 = Release|Any CPU {E8843255-77EB-471F-B682-528BB4B5D1D5}.Release|x86.ActiveCfg = Release|Any CPU {E8843255-77EB-471F-B682-528BB4B5D1D5}.Release|x86.Build.0 = Release|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Debug|x64.ActiveCfg = Debug|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Debug|x64.Build.0 = Debug|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Debug|x86.ActiveCfg = Debug|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Debug|x86.Build.0 = Debug|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Release|Any CPU.Build.0 = Release|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Release|x64.ActiveCfg = Release|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Release|x64.Build.0 = Release|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Release|x86.ActiveCfg = Release|Any CPU + {0FD6B6D1-00AB-42CF-800F-4039A976A75A}.Release|x86.Build.0 = Release|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Debug|x64.ActiveCfg = Debug|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Debug|x64.Build.0 = Debug|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Debug|x86.ActiveCfg = Debug|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Debug|x86.Build.0 = Debug|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Release|Any CPU.Build.0 = Release|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Release|x64.ActiveCfg = Release|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Release|x64.Build.0 = Release|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Release|x86.ActiveCfg = Release|Any CPU + {726D5295-3F4E-4A1A-8F3B-0EA8EC456B48}.Release|x86.Build.0 = Release|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Debug|x64.ActiveCfg = Debug|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Debug|x64.Build.0 = Debug|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Debug|x86.ActiveCfg = Debug|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Debug|x86.Build.0 = Debug|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Release|Any CPU.Build.0 = Release|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Release|x64.ActiveCfg = Release|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Release|x64.Build.0 = Release|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Release|x86.ActiveCfg = Release|Any CPU + {3DB2E3F5-0DBE-4B91-A335-D82F8794324B}.Release|x86.Build.0 = Release|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Debug|x64.ActiveCfg = Debug|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Debug|x64.Build.0 = Debug|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Debug|x86.ActiveCfg = Debug|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Debug|x86.Build.0 = Debug|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Release|Any CPU.Build.0 = Release|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Release|x64.ActiveCfg = Release|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Release|x64.Build.0 = Release|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Release|x86.ActiveCfg = Release|Any CPU + {21AA751A-4C29-414C-B476-EE9204A48DDD}.Release|x86.Build.0 = Release|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Debug|x64.ActiveCfg = Debug|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Debug|x64.Build.0 = Debug|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Debug|x86.ActiveCfg = Debug|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Debug|x86.Build.0 = Debug|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Release|Any CPU.Build.0 = Release|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Release|x64.ActiveCfg = Release|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Release|x64.Build.0 = Release|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Release|x86.ActiveCfg = Release|Any CPU + {07674D84-4A5C-4608-BECE-03630D38275F}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Core/Core/InternalsVisibleTo.cs b/src/Core/Core/InternalsVisibleTo.cs new file mode 100644 index 00000000000..ada8fca1944 --- /dev/null +++ b/src/Core/Core/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("HotChocolate.Types.Selections")] diff --git a/src/Core/PersistedQueries.Redis.Tests/PersistedQueries.Redis.Tests.csproj b/src/Core/PersistedQueries.Redis.Tests/PersistedQueries.Redis.Tests.csproj index 50466573a23..651a12359b7 100644 --- a/src/Core/PersistedQueries.Redis.Tests/PersistedQueries.Redis.Tests.csproj +++ b/src/Core/PersistedQueries.Redis.Tests/PersistedQueries.Redis.Tests.csproj @@ -21,7 +21,7 @@ - + diff --git a/src/Core/Subscriptions.Redis.Tests/Subscriptions.Redis.Tests.csproj b/src/Core/Subscriptions.Redis.Tests/Subscriptions.Redis.Tests.csproj index 0350219d097..87e42e88435 100644 --- a/src/Core/Subscriptions.Redis.Tests/Subscriptions.Redis.Tests.csproj +++ b/src/Core/Subscriptions.Redis.Tests/Subscriptions.Redis.Tests.csproj @@ -23,7 +23,7 @@ - + diff --git a/src/Core/Types.Filters.Mongo.Tests/Types.Filters.Mongo.Tests.csproj b/src/Core/Types.Filters.Mongo.Tests/Types.Filters.Mongo.Tests.csproj index c337ed835ad..e2a98914ed8 100644 --- a/src/Core/Types.Filters.Mongo.Tests/Types.Filters.Mongo.Tests.csproj +++ b/src/Core/Types.Filters.Mongo.Tests/Types.Filters.Mongo.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/Core/Types.Filters/QueryableFilterMiddleware.cs b/src/Core/Types.Filters/QueryableFilterMiddleware.cs index d0699b72828..4deffc33153 100644 --- a/src/Core/Types.Filters/QueryableFilterMiddleware.cs +++ b/src/Core/Types.Filters/QueryableFilterMiddleware.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -26,7 +26,7 @@ public async Task InvokeAsync(IMiddlewareContext context) { await _next(context).ConfigureAwait(false); - var filter = context.Argument("where"); + IValueNode filter = context.Argument("where"); if (filter is null || filter is NullValueNode) { diff --git a/src/Core/Types.Filters/QueryableFilterVisitor.cs b/src/Core/Types.Filters/QueryableFilterVisitor.cs index 155f2d9fedb..2475c42187f 100644 --- a/src/Core/Types.Filters/QueryableFilterVisitor.cs +++ b/src/Core/Types.Filters/QueryableFilterVisitor.cs @@ -64,6 +64,11 @@ public Expression> CreateFilter() _parameter); } + public Expression CreateFilter() + { + return Expression.Lambda(Level.Peek().Peek(), _parameter); + } + protected Stack> Level { get; } = new Stack>(); diff --git a/src/Core/Types.Selection.Abstractions.Tests/IResolverProvider.cs b/src/Core/Types.Selection.Abstractions.Tests/IResolverProvider.cs new file mode 100644 index 00000000000..7a6dd24c00f --- /dev/null +++ b/src/Core/Types.Selection.Abstractions.Tests/IResolverProvider.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using HotChocolate.Resolvers; +using Microsoft.Extensions.DependencyInjection; + +namespace HotChocolate.Types.Selections +{ + public interface IResolverProvider + { + public (IServiceCollection, Func>) + CreateResolver(params TResult[] results) + where TResult : class; + } +} diff --git a/src/Core/Types.Selection.Abstractions.Tests/SelectionAttributeTestsBase.cs b/src/Core/Types.Selection.Abstractions.Tests/SelectionAttributeTestsBase.cs new file mode 100644 index 00000000000..3eb873d52b8 --- /dev/null +++ b/src/Core/Types.Selection.Abstractions.Tests/SelectionAttributeTestsBase.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using HotChocolate.Execution; +using HotChocolate.Resolvers; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace HotChocolate.Types.Selections +{ + public abstract class SelectionAttributeTestsBase + { + + private readonly IResolverProvider _provider; + private readonly bool _setId; + + protected SelectionAttributeTestsBase(IResolverProvider provider, bool setId = false) + { + _provider = provider; + _setId = setId; + } + + [Fact] + public void Execute_Selection_MultipleScalar() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver( + Foo.Create("aa", 1, _setId), + Foo.Create("bb", 2, _setId)); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType(d => + d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + })) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { bar baz } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Equal("aa", x.Bar); + Assert.Equal(1, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.NestedCollection); + }, + x => + { + Assert.Equal("bb", x.Bar); + Assert.Equal(2, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.NestedCollection); + }); + } + + public class Query + { + [UseSelection] + public IQueryable Foos { get; } + } + + public class Foo + { + private static int idCounter = 1; + + [Key] + public int Id { get; set; } + + public string Bar { get; set; } + + public int Baz { get; set; } + + public NestedFoo Nested { get; set; } + + public List NestedCollection { get; set; } + + public static Foo Create(string bar, int baz, bool setId) + { + var value = new Foo + { + Bar = bar, + Baz = baz, + Nested = new NestedFoo() + { + Bar = "nested" + bar, + Baz = baz * 2 + }, + NestedCollection = new List() + { + new NestedFoo() + { + Bar = "nestedcollection" + bar, + Baz = baz * 3 + }, + } + }; + if (setId) + { + value.Id = ++idCounter; + } + return value; + } + } + + public class NestedFoo + { + [Key] + public int Id { get; set; } + + public string Bar { get; set; } + + public int Baz { get; set; } + } + } +} diff --git a/src/Core/Types.Selection.Abstractions.Tests/SelectionTestsBase.cs b/src/Core/Types.Selection.Abstractions.Tests/SelectionTestsBase.cs new file mode 100644 index 00000000000..ceae93cd69c --- /dev/null +++ b/src/Core/Types.Selection.Abstractions.Tests/SelectionTestsBase.cs @@ -0,0 +1,1151 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using HotChocolate.Execution; +using HotChocolate.Resolvers; +using HotChocolate.Types.Relay; +using Xunit; + +namespace HotChocolate.Types.Selections +{ + public abstract class SelectionTestsBase + { + private readonly static Foo[] SAMPLE = + new[] { + Foo.Create("aa", 1), + Foo.Create("bb", 2) }; + + private readonly IResolverProvider _provider; + + protected SelectionTestsBase(IResolverProvider provider) + { + _provider = provider; + } + + [Fact] + public virtual void Execute_Selection_Fragment() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { ...test } } fragment test on Foo { bar baz}"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Equal("aa", x.Bar); + Assert.Equal(1, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }, + x => + { + Assert.Equal("bb", x.Bar); + Assert.Equal(2, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }); + } + + [Fact] + public virtual void Execute_Selection_Scalar() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { bar } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Equal("aa", x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }, + x => + { + Assert.Equal("bb", x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }); + } + + [Fact] + public virtual void Execute_Selection_MultipleScalar() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { bar baz } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Equal("aa", x.Bar); + Assert.Equal(1, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }, + x => + { + Assert.Equal("bb", x.Bar); + Assert.Equal(2, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }); + } + + [Fact] + public virtual void Execute_Selection_Object() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { nested { bar } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.NotNull(x.Nested); + Assert.Equal("nestedaa", x.Nested.Bar); + Assert.Equal(0, x.Nested.Baz); + Assert.Null(x.ObjectArray); + }, + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.NotNull(x.Nested); + Assert.Equal("nestedbb", x.Nested.Bar); + Assert.Equal(0, x.Nested.Baz); + Assert.Null(x.ObjectArray); + }); + } + + [Fact] + public virtual void Execute_Selection_Array() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { objectArray { bar } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.ObjectArray); + Assert.Equal("objectArrayaa", x.ObjectArray[0].Bar); + Assert.Equal(0, x.ObjectArray[0].Baz); + }, + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.ObjectArray); + Assert.Equal("objectArraybb", x.ObjectArray[0].Bar); + Assert.Equal(0, x.ObjectArray[0].Baz); + }); + } + + [Fact] + public virtual void Execute_Selection_List() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { objectList { bar } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.ObjectList); + Assert.Equal("objectListaa", x.ObjectList[0].Bar); + Assert.Equal(0, x.ObjectList[0].Baz); + }, + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.ObjectList); + Assert.Equal("objectListbb", x.ObjectList[0].Bar); + Assert.Equal(0, x.ObjectList[0].Baz); + }); + } + + [Fact] + public virtual void Execute_Selection_List_Interface() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { iObjectList { bar } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.IObjectList); + Assert.Equal("iListaa", x.IObjectList[0].Bar); + Assert.Equal(0, x.IObjectList[0].Baz); + }, + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.IObjectList); + Assert.Equal("iListbb", x.IObjectList[0].Bar); + Assert.Equal(0, x.IObjectList[0].Baz); + }); + } + + [Fact] + public virtual void Execute_Selection_Set_Interface() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { iSet { bar } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.ISet); + Assert.Equal("iSetaa", x.ISet.First().Bar); + Assert.Equal(0, x.ISet.First().Baz); + }, + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.ISet); + Assert.Equal("iSetbb", x.ISet.First().Bar); + Assert.Equal(0, x.ISet.First().Baz); + }); + } + + [Fact] + public virtual void Execute_Selection_Set() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { hashSet { bar } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.HashSet); + Assert.Equal("hashSetaa", x.HashSet.First().Bar); + Assert.Equal(0, x.HashSet.First().Baz); + }, + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.HashSet); + Assert.Equal("hashSetbb", x.HashSet.First().Bar); + Assert.Equal(0, x.HashSet.First().Baz); + }); + } + + [Fact] + public virtual void Execute_Selection_SortedSet() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { sortedSet { bar } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.SortedSet); + Assert.Equal("sortedSetaa", x.SortedSet.First().Bar); + Assert.Equal(0, x.SortedSet.First().Baz); + }, + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.SortedSet); + Assert.Equal("sortedSetbb", x.SortedSet.First().Bar); + Assert.Equal(0, x.SortedSet.First().Baz); + }); + } + + [Fact] + public virtual void Execute_Selection_ObjectDeep() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { nested { nested { nested { nested { bar } } } } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.NotNull(x.Nested); + Assert.Equal(0, x.Nested.Baz); + Assert.Null(x.ObjectArray); + Assert.Null(x.Nested.ObjectArray); + Assert.Null(x.Nested.Nested.Bar); + Assert.Null(x.Nested.Nested.Nested.Bar); + Assert.Equal("recursiveaa", x.Nested.Nested.Nested.Nested.Bar); + }, + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.NotNull(x.Nested); + Assert.Equal(0, x.Nested.Baz); + Assert.Null(x.ObjectArray); + Assert.Null(x.Nested.ObjectArray); + Assert.Null(x.Nested.Nested.Bar); + Assert.Null(x.Nested.Nested.Nested.Bar); + Assert.Equal("recursivebb", x.Nested.Nested.Nested.Nested.Bar); + }); + } + + [Fact] + public virtual void Execute_Selection_ArrayDeep() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + executor.Execute( + "{ foos { objectArray { objectArray { objectArray { bar } } } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray(), + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.ObjectArray); + Assert.Null(x.ObjectArray[0].Bar); + Assert.Null(x.ObjectArray[0].ObjectArray[0].Bar); + Assert.Equal( + "recursiveaa", + x.ObjectArray[0].ObjectArray[0].ObjectArray[0].Bar); + Assert.Equal(0, x.ObjectArray[0].Baz); + }, + x => + { + Assert.Null(x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Single(x.ObjectArray); + Assert.Null(x.ObjectArray[0].Bar); + Assert.Null(x.ObjectArray[0].ObjectArray[0].Bar); + Assert.Equal( + "recursivebb", + x.ObjectArray[0].ObjectArray[0].ObjectArray[0].Bar); + Assert.Equal(0, x.ObjectArray[0].Baz); + }); + } + + [Fact] + public virtual void Execute_Selection_Object_Paging_Nodes() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + Connection resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as Connection; + }) + .UsePaging>() + .UseFiltering() + .UseSorting() + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = executor.Execute( + "{ foos { nodes { nested { bar } } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.Edges.ToArray(), + x => + { + Assert.Null(x.Node.Bar); + Assert.Equal(0, x.Node.Baz); + Assert.NotNull(x.Node.Nested); + Assert.Equal("nestedaa", x.Node.Nested.Bar); + Assert.Equal(0, x.Node.Nested.Baz); + Assert.Null(x.Node.ObjectArray); + }, + x => + { + Assert.Null(x.Node.Bar); + Assert.Equal(0, x.Node.Baz); + Assert.NotNull(x.Node.Nested); + Assert.Equal("nestedbb", x.Node.Nested.Bar); + Assert.Equal(0, x.Node.Nested.Baz); + Assert.Null(x.Node.ObjectArray); + }); + } + + [Fact] + public virtual void Execute_Selection_Object_Paging_Edges() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + Connection resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as Connection; + }) + .UsePaging>() + .UseFiltering() + .UseSorting() + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = executor.Execute( + "{ foos { edges { node { bar }} } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.Edges.ToArray(), + x => + { + Assert.Equal("aa", x.Node.Bar); + Assert.Equal(0, x.Node.Baz); + Assert.Null(x.Node.Nested); + Assert.Null(x.Node.ObjectArray); + }, + x => + { + Assert.Equal("bb", x.Node.Bar); + Assert.Equal(0, x.Node.Baz); + Assert.Null(x.Node.Nested); + Assert.Null(x.Node.ObjectArray); + }); + } + + [Fact] + public virtual void Execute_Selection_Object_Paging_Combined() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + Connection resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as Connection; + }) + .UsePaging>() + .UseFiltering() + .UseSorting() + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = executor.Execute( + "{ foos { nodes { nested { bar } } edges { node { bar }} } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.Edges.ToArray(), + x => + { + Assert.Equal("aa", x.Node.Bar); + Assert.Equal(0, x.Node.Baz); + Assert.NotNull(x.Node.Nested); + Assert.Equal("nestedaa", x.Node.Nested.Bar); + Assert.Equal(0, x.Node.Nested.Baz); + Assert.Null(x.Node.ObjectArray); + }, + x => + { + Assert.Equal("bb", x.Node.Bar); + Assert.Equal(0, x.Node.Baz); + Assert.NotNull(x.Node.Nested); + Assert.Equal("nestedbb", x.Node.Nested.Bar); + Assert.Equal(0, x.Node.Nested.Baz); + Assert.Null(x.Node.ObjectArray); + }); + } + + [Fact] + public virtual void Execute_Selection_DeepPaging() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseFiltering() + .UseSorting() + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = executor.Execute( + "{ foos { middlewareList { nodes { bar } } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray()[0].MiddlewareList, + x => + { + Assert.Equal("aa", x.Bar.Substring(2)); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }, + x => + { + Assert.Equal("aa", x.Bar.Substring(2)); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }, + x => + { + Assert.Equal("aa", x.Bar.Substring(2)); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }); + } + + [Fact] + public virtual void Execute_Selection_Nested_Filtering() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseFiltering() + .UseSorting() + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = executor.Execute( + "{ foos { middlewareList(where:{bar: \"ccaa\"}) { nodes { bar } } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Single(resultCtx.ToArray()[0].MiddlewareList); + Assert.Collection(resultCtx.ToArray()[0].MiddlewareList, + x => + { + Assert.Equal("ccaa", x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }); + } + + [Fact] + public virtual void Execute_Selection_Nested_Sorting() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseFiltering() + .UseSorting() + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = executor.Execute( + "{ foos { middlewareList(order_by:{baz: ASC, bar: ASC}) { nodes { bar } } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray()[0].MiddlewareList, + x => + { + Assert.Equal("aaaa", x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }, + x => + { + Assert.Equal("ccaa", x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }, + x => + { + Assert.Equal("bbaa", x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }); + } + + [Fact] + public virtual void Execute_Selection_Nested_FilteringAndSorting() + { + // arrange + IServiceCollection services; + Func> resolver; + (services, resolver) = _provider.CreateResolver(SAMPLE); + + IQueryable resultCtx = null; + ISchema schema = SchemaBuilder.New() + .AddServices(services.BuildServiceProvider()) + .AddQueryType( + d => d.Field(t => t.Foos) + .Resolver(resolver) + .Use(next => async ctx => + { + await next(ctx).ConfigureAwait(false); + resultCtx = ctx.Result as IQueryable; + }) + .UseFiltering() + .UseSorting() + .UseSelection()) + .Create(); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = executor.Execute( + "{ foos { middlewareList(where: {bar_in:[\"aaaa\",\"bbaa\"]}, " + + "order_by:{baz: ASC, bar: ASC}) { nodes { bar } } } }"); + + // assert + Assert.NotNull(resultCtx); + Assert.Collection(resultCtx.ToArray()[0].MiddlewareList, + x => + { + Assert.Equal("aaaa", x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }, + x => + { + Assert.Equal("bbaa", x.Bar); + Assert.Equal(0, x.Baz); + Assert.Null(x.Nested); + Assert.Null(x.ObjectArray); + }); + } + + public class Query + { + public IQueryable Foos { get; } + } + + public class Foo + { + [Key] + public Guid Id { get; set; } + + public string Bar { get; set; } + + public int Baz { get; set; } + + public NestedFoo Nested { get; set; } + + public NestedFoo[] ObjectArray { get; set; } + + public List ObjectList { get; set; } + + public IList IObjectList { get; set; } + + public HashSet HashSet { get; set; } + + public SortedSet SortedSet { get; set; } + + public ISet ISet { get; set; } + + [UsePaging] + [UseFiltering] + [UseSorting] + public List MiddlewareList { get; set; } + + public static Foo Create(string bar, int baz) + { + var recursive = new NestedFoo() + { + Bar = "recursive" + bar, + Baz = 10 + }; + var recursive2 = new NestedFoo() + { + Bar = "recursive" + bar, + Baz = 10 + }; + for (var level = 0; level < 10; level++) + { + recursive = new NestedFoo() + { + Bar = "recursive" + bar, + Baz = 10, + Nested = recursive.Clone(), + ObjectArray = new List { recursive2.Clone() } + }; + + recursive2 = new NestedFoo() + { + Bar = "recursive" + bar, + Baz = 10, + Nested = recursive.Clone(), + ObjectArray = new List { recursive2.Clone() } + }; + } + return new Foo + { + Bar = bar, + Baz = baz, + Nested = new NestedFoo() + { + Bar = "nested" + bar, + Baz = baz * 2, + Nested = recursive.Clone(), + ObjectArray = new List { recursive2.Clone() } + }, + ObjectArray = new NestedFoo[] + { + new NestedFoo() + { + Bar = "objectArray" + bar, + Baz = baz * 3, + Nested = recursive.Clone(), + ObjectArray = new List { recursive2.Clone() } + }, + }, + ObjectList = new List + { + new NestedFoo() + { + Bar = "objectList" + bar, + Baz = baz * 3 + }, + }, + IObjectList = new List + { + new NestedFoo() + { + Bar = "iList" + bar, + Baz = baz * 3 + }, + }, + HashSet = new HashSet + { + new NestedFoo() + { + Bar = "hashSet" + bar, + Baz = baz * 3 + }, + }, + SortedSet = new SortedSet + { + new NestedFoo() + { + Bar = "sortedSet" + bar, + Baz = baz * 3 + }, + }, + ISet = new HashSet + { + new NestedFoo() + { + Bar = "iSet" + bar, + Baz = baz * 3 + }, + }, + MiddlewareList = new List + { + new NestedFoo() + { + Bar = "cc" + bar, + Baz = baz * 1 + }, + new NestedFoo() + { + Bar = "aa" + bar, + Baz = baz * 1 + }, + new NestedFoo() + { + Bar = "bb" + bar, + Baz = baz * 2 + }, + } + }; + } + } + + public class NestedFoo + { + [Key] + public int Id { get; set; } + + public string Bar { get; set; } + + public int Baz { get; set; } + + public NestedFoo Nested { get; set; } + + public List ObjectArray { get; set; } + + public NestedFoo Clone() + { + NestedFoo clone = (NestedFoo)base.MemberwiseClone(); + return clone; + } + } + } +} diff --git a/src/Core/Types.Selection.Abstractions.Tests/Types.Selection.Abstractions.Tests.csproj b/src/Core/Types.Selection.Abstractions.Tests/Types.Selection.Abstractions.Tests.csproj new file mode 100644 index 00000000000..0813588003d --- /dev/null +++ b/src/Core/Types.Selection.Abstractions.Tests/Types.Selection.Abstractions.Tests.csproj @@ -0,0 +1,26 @@ + + + + netcoreapp2.0 + $(MSBuildThisFileDirectory.TrimEnd('\').TrimEnd('/')) + $([System.IO.Path]::Combine($(ChilliCurrentDirectory), '..', '..', '..', 'tools')) + $([System.IO.Path]::Combine($(ChilliImport), 'CoreTestFramework.props')) + $([System.IO.Path]::Combine($(ChilliImport), 'TestSettings.props')) + + + + + + + HotChocolate.Types.Selections.Abstractions.Tests + HotChocolate.Types.Selections + + + + + + + + + + diff --git a/src/Core/Types.Selection.InMemory.Tests/InMemoryProvider.cs b/src/Core/Types.Selection.InMemory.Tests/InMemoryProvider.cs new file mode 100644 index 00000000000..20044680de3 --- /dev/null +++ b/src/Core/Types.Selection.InMemory.Tests/InMemoryProvider.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using HotChocolate.Resolvers; + +namespace HotChocolate.Types.Selections +{ + public class InMemoryProvider : IResolverProvider + { + public (IServiceCollection, Func>) + CreateResolver(params TResult[] results) where TResult : class + { + var services = new ServiceCollection(); + return (services, ctx => results); + } + } +} diff --git a/src/Core/Types.Selection.InMemory.Tests/SelectionAttributeTests.cs b/src/Core/Types.Selection.InMemory.Tests/SelectionAttributeTests.cs new file mode 100644 index 00000000000..5ba6d2704f5 --- /dev/null +++ b/src/Core/Types.Selection.InMemory.Tests/SelectionAttributeTests.cs @@ -0,0 +1,13 @@ +using Xunit; + +namespace HotChocolate.Types.Selections +{ + public class SelectionAttributeTests + : SelectionAttributeTestsBase + , IClassFixture + { + public SelectionAttributeTests(InMemoryProvider provider) : base(provider) + { + } + } +} diff --git a/src/Core/Types.Selection.InMemory.Tests/SelectionTests.cs b/src/Core/Types.Selection.InMemory.Tests/SelectionTests.cs new file mode 100644 index 00000000000..896be6ef8d5 --- /dev/null +++ b/src/Core/Types.Selection.InMemory.Tests/SelectionTests.cs @@ -0,0 +1,13 @@ +using Xunit; + +namespace HotChocolate.Types.Selections +{ + public class SelectionTests + : SelectionTestsBase + , IClassFixture + { + public SelectionTests(InMemoryProvider provider) : base(provider) + { + } + } +} diff --git a/src/Core/Types.Selection.InMemory.Tests/Types.Selection.InMemory.Tests.csproj b/src/Core/Types.Selection.InMemory.Tests/Types.Selection.InMemory.Tests.csproj new file mode 100644 index 00000000000..4ec00b13785 --- /dev/null +++ b/src/Core/Types.Selection.InMemory.Tests/Types.Selection.InMemory.Tests.csproj @@ -0,0 +1,23 @@ + + + + netcoreapp2.0 + $(MSBuildThisFileDirectory.TrimEnd('\').TrimEnd('/')) + $([System.IO.Path]::Combine($(ChilliCurrentDirectory), '..', '..', '..', 'tools')) + $([System.IO.Path]::Combine($(ChilliImport), 'CoreTestFramework.props')) + $([System.IO.Path]::Combine($(ChilliImport), 'TestSettings.props')) + + + + + + + HotChocolate.Types.Selections.InMemory.Tests + HotChocolate.Types.Selections + + + + + + + diff --git a/src/Core/Types.Selection.Mongo.Tests/MongoProvider.cs b/src/Core/Types.Selection.Mongo.Tests/MongoProvider.cs new file mode 100644 index 00000000000..ce0380e6ca4 --- /dev/null +++ b/src/Core/Types.Selection.Mongo.Tests/MongoProvider.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using HotChocolate.Resolvers; +using Microsoft.Extensions.DependencyInjection; +using MongoDB.Driver; +using Squadron; + +namespace HotChocolate.Types.Selections +{ + public class MongoProvider : IResolverProvider + { + private readonly MongoResource _resource; + + public MongoProvider(MongoResource resource) + { + _resource = resource; + } + + public (IServiceCollection, Func>) + CreateResolver(params TResult[] results) + where TResult : class + { + var services = new ServiceCollection(); + IMongoDatabase database = _resource.CreateDatabase(); + IMongoCollection collection = database.GetCollection("col"); + collection.InsertMany(results); + + services.AddSingleton>(collection); + + return (services, ctx => ctx.Service>().AsQueryable()); + } + } +} diff --git a/src/Core/Types.Selection.Mongo.Tests/SelectionAttributeTests.cs b/src/Core/Types.Selection.Mongo.Tests/SelectionAttributeTests.cs new file mode 100644 index 00000000000..e8d725d22fb --- /dev/null +++ b/src/Core/Types.Selection.Mongo.Tests/SelectionAttributeTests.cs @@ -0,0 +1,14 @@ +using Squadron; +using Xunit; + +namespace HotChocolate.Types.Selections +{ + public class SelectionAttributeTests + : SelectionAttributeTestsBase, IClassFixture + { + public SelectionAttributeTests(MongoResource provider) + : base(new MongoProvider(provider), true) + { + } + } +} diff --git a/src/Core/Types.Selection.Mongo.Tests/SelectionTests.cs b/src/Core/Types.Selection.Mongo.Tests/SelectionTests.cs new file mode 100644 index 00000000000..0e4a651e8ab --- /dev/null +++ b/src/Core/Types.Selection.Mongo.Tests/SelectionTests.cs @@ -0,0 +1,69 @@ +using Squadron; +using Xunit; + +namespace HotChocolate.Types.Selections +{ + public class SelectionTests + : SelectionTestsBase + , IClassFixture + { + public SelectionTests(MongoResource provider) + : base(new MongoProvider(provider)) + { + } + + [Fact(Skip = "Not yet supported!")] + public override void Execute_Selection_Array() + { + } + + [Fact(Skip = "Not yet supported!")] + public override void Execute_Selection_ArrayDeep() + { + } + + [Fact(Skip = "Not yet supported!")] + public override void Execute_Selection_DeepPaging() + { + } + + [Fact(Skip = "Not yet supported!")] + public override void Execute_Selection_List() + { + } + + [Fact(Skip = "Not yet supported!")] + public override void Execute_Selection_List_Interface() + { + } + [Fact(Skip = "Not yet supported!")] + public override void Execute_Selection_Set() + { + } + + [Fact(Skip = "Not yet supported!")] + public override void Execute_Selection_Set_Interface() + { + } + + [Fact(Skip = "Not yet supported!")] + public override void Execute_Selection_Nested_Filtering() + { + } + + [Fact(Skip = "Not yet supported!")] + public override void Execute_Selection_Nested_FilteringAndSorting() + { + } + + [Fact(Skip = "Not yet supported!")] + public override void Execute_Selection_Nested_Sorting() + { + } + + [Fact(Skip = "Not yet supported!")] + public override void Execute_Selection_SortedSet() + { + } + } +} diff --git a/src/Core/Types.Selection.Mongo.Tests/Types.Selection.Mongo.Tests.csproj b/src/Core/Types.Selection.Mongo.Tests/Types.Selection.Mongo.Tests.csproj new file mode 100644 index 00000000000..4dd1882cb6e --- /dev/null +++ b/src/Core/Types.Selection.Mongo.Tests/Types.Selection.Mongo.Tests.csproj @@ -0,0 +1,27 @@ + + + + netcoreapp2.0 + $(MSBuildThisFileDirectory.TrimEnd('\').TrimEnd('/')) + $([System.IO.Path]::Combine($(ChilliCurrentDirectory), '..', '..', '..', 'tools')) + $([System.IO.Path]::Combine($(ChilliImport), 'CoreTestFramework.props')) + $([System.IO.Path]::Combine($(ChilliImport), 'TestSettings.props')) + + + + + + + HotChocolate.Types.Selections.Mongo.Tests + HotChocolate.Types.Selections + + + + + + + + + + + diff --git a/src/Core/Types.Selection.SqlServer.Tests/SelectionAttributeTests.txt b/src/Core/Types.Selection.SqlServer.Tests/SelectionAttributeTests.txt new file mode 100644 index 00000000000..8a873eea834 --- /dev/null +++ b/src/Core/Types.Selection.SqlServer.Tests/SelectionAttributeTests.txt @@ -0,0 +1,15 @@ +using Squadron; +using Xunit; + +namespace HotChocolate.Types.Selections +{ + public class SelectionAttributeTests + : SelectionAttributeTestsBase + , IClassFixture + { + public SelectionAttributeTests(SqlServerResource provider) + : base(new SqlServerProvider(provider)) + { + } + } +} diff --git a/src/Core/Types.Selection.SqlServer.Tests/SelectionTests.txt b/src/Core/Types.Selection.SqlServer.Tests/SelectionTests.txt new file mode 100644 index 00000000000..1ab73b1d7cf --- /dev/null +++ b/src/Core/Types.Selection.SqlServer.Tests/SelectionTests.txt @@ -0,0 +1,27 @@ +using Squadron; +using Xunit; + +namespace HotChocolate.Types.Selections +{ + public class SelectionTests + : SelectionTestsBase + , IClassFixture + { + public SelectionTests(SqlServerResource provider) + : base(new SqlServerProvider(provider)) + { + } + + public override void Execute_Selection_Array() + { + // EF does not support array + Assert.True(true); + } + + public override void Execute_Selection_ArrayDeep() + { + // EF does not support array + Assert.True(true); + } + } +} diff --git a/src/Core/Types.Selection.SqlServer.Tests/SqlServerProvider.txt b/src/Core/Types.Selection.SqlServer.Tests/SqlServerProvider.txt new file mode 100644 index 00000000000..f1892b7a5be --- /dev/null +++ b/src/Core/Types.Selection.SqlServer.Tests/SqlServerProvider.txt @@ -0,0 +1,95 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using HotChocolate.Resolvers; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Squadron; + +namespace HotChocolate.Types.Selections +{ + public class SqlServerProvider : IResolverProvider + { + private static readonly ILoggerFactory ConsoleLogger = + LoggerFactory.Create(x => x.AddConsole()); + + private static readonly ConcurrentDictionary _cache = + new ConcurrentDictionary(); + + private readonly SqlServerResource _resource; + + public SqlServerProvider(SqlServerResource resource) + { + _resource = resource; + } + + public (IServiceCollection, Func>) + CreateResolver(params TResult[] results) + where TResult : class + { + if (_cache.GetOrAdd(results, (obj) => BuildResolver(results)) + is ValueTuple>> result) + { + return result; + } + throw new InvalidOperationException("Cache is in invalid state!"); + } + + private (IServiceCollection, Func>) + BuildResolver(params TResult[] results) + where TResult : class + { + var dbContext = new DatabaseContext( + _resource.CreateDatabaseAsync( + $"CREATE DATABASE useSelection", + $"useSelection") + .GetAwaiter() + .GetResult()); + dbContext.Database.EnsureCreated(); + dbContext.Data.AddRange(results); + dbContext.SaveChanges(); + + var services = new ServiceCollection(); + services.AddSingleton(dbContext); + + return (services, ctx => ctx.Service>().Data.AsQueryable()); + } + + private class DatabaseContext : DbContext + where TResult : class + { + private readonly string _connectionString; + + public DatabaseContext(string connectionString) + { + _connectionString = connectionString; + } + + public DbSet Data { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder + .UseSqlServer(_connectionString) + .EnableSensitiveDataLogging() + .UseLoggerFactory(ConsoleLogger); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .Ignore(x => x.ObjectArray); + } + } + + public class SelectionAttributeTestsBaseFooNested + { + public Guid FooId { get; set; } + public SelectionAttributeTestsBase.Foo Foo { get; set; } + public Guid NestedFooId { get; set; } + public SelectionAttributeTestsBase.NestedFoo NestedFoo { get; set; } + } + } +} diff --git a/src/Core/Types.Selection.SqlServer.Tests/Types.Selection.SqlServer.Tests.csproj b/src/Core/Types.Selection.SqlServer.Tests/Types.Selection.SqlServer.Tests.csproj new file mode 100644 index 00000000000..2a44050639e --- /dev/null +++ b/src/Core/Types.Selection.SqlServer.Tests/Types.Selection.SqlServer.Tests.csproj @@ -0,0 +1,31 @@ + + + + netcoreapp2.0 + $(MSBuildThisFileDirectory.TrimEnd('\').TrimEnd('/')) + $([System.IO.Path]::Combine($(ChilliCurrentDirectory), '..', '..', '..', 'tools')) + $([System.IO.Path]::Combine($(ChilliImport), 'CoreTestFramework.props')) + $([System.IO.Path]::Combine($(ChilliImport), 'TestSettings.props')) + + + + + + + HotChocolate.Types.Selections.SqlServer.Tests + HotChocolate.Types.Selections + + + + + + + + + + + + + + + diff --git a/src/Core/Types.Selection/Extensions/SelectionObjectFieldDescriptorExtensions.cs b/src/Core/Types.Selection/Extensions/SelectionObjectFieldDescriptorExtensions.cs new file mode 100644 index 00000000000..3382b8bb6cd --- /dev/null +++ b/src/Core/Types.Selection/Extensions/SelectionObjectFieldDescriptorExtensions.cs @@ -0,0 +1,90 @@ +using System; +using System.Threading.Tasks; +using HotChocolate.Resolvers; +using HotChocolate.Types.Descriptors; +using HotChocolate.Types.Descriptors.Definitions; +using HotChocolate.Utilities; + +namespace HotChocolate.Types +{ + public static class SelectionObjectFieldDescriptorExtensions + { + private static readonly Type _middlewareDefinition = typeof(SelectionMiddleware<>); + + public static IObjectFieldDescriptor UseSelection( + this IObjectFieldDescriptor descriptor) + { + if (descriptor is null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + return UseSelection(descriptor, null); + } + + public static IObjectFieldDescriptor UseSelection( + this IObjectFieldDescriptor descriptor) + { + if (descriptor is null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + return UseSelection(descriptor, typeof(T)); + } + + private static IObjectFieldDescriptor UseSelection( + IObjectFieldDescriptor descriptor, + Type objectType) + { + FieldMiddleware placeholder = + next => context => Task.CompletedTask; + + descriptor + .Use(placeholder) + .Extend() + .OnBeforeCreate(definition => + { + Type selectionType = objectType; + + if (objectType == null) + { + if (!TypeInspector.Default.TryCreate( + definition.ResultType, out TypeInfo typeInfo)) + { + // TODO : resources + throw new ArgumentException( + "Cannot handle the specified type.", + nameof(descriptor)); + } + + selectionType = typeInfo.ClrType; + } + + ILazyTypeConfiguration lazyConfiguration = + LazyTypeConfigurationBuilder + .New() + .Definition(definition) + .Configure((context, defintion) => + CompileMiddleware( + selectionType, + definition, + placeholder)) + .On(ApplyConfigurationOn.Completion) + .Build(); + definition.Configurations.Add(lazyConfiguration); + }); + + return descriptor; + } + + private static void CompileMiddleware( + Type type, + ObjectFieldDefinition definition, + FieldMiddleware placeholder) + { + Type middlewareType = _middlewareDefinition.MakeGenericType(type); + FieldMiddleware middleware = FieldClassMiddlewareFactory.Create(middlewareType); + int index = definition.MiddlewareComponents.IndexOf(placeholder); + definition.MiddlewareComponents[index] = middleware; + } + } +} diff --git a/src/Core/Types.Selection/Handler/FilterHandler.cs b/src/Core/Types.Selection/Handler/FilterHandler.cs new file mode 100644 index 00000000000..b7b0e1b5aba --- /dev/null +++ b/src/Core/Types.Selection/Handler/FilterHandler.cs @@ -0,0 +1,36 @@ +using System.Linq; +using System.Linq.Expressions; +using HotChocolate.Language; +using HotChocolate.Resolvers; +using HotChocolate.Types.Filters; + +namespace HotChocolate.Types.Selections +{ + public class FilterHandler : IListHandler + { + public Expression HandleLeave( + SelectionVisitorContext context, + IFieldSelection selection, + Expression expression) + { + if (context.TryGetValueNode("where", out IValueNode filter) && + selection.Field.Arguments["where"].Type is InputObjectType iot && + iot is IFilterInputType fit) + { + var visitor = new QueryableFilterVisitor( + iot, fit.EntityType, context.Conversion); + + filter.Accept(visitor); + + return Expression.Call( + typeof(Enumerable), + "Where", + new[] { fit.EntityType }, + expression, + visitor.CreateFilter()); + } + + return expression; + } + } +} diff --git a/src/Core/Types.Selection/Handler/IListHandler.cs b/src/Core/Types.Selection/Handler/IListHandler.cs new file mode 100644 index 00000000000..3c560ecf4ed --- /dev/null +++ b/src/Core/Types.Selection/Handler/IListHandler.cs @@ -0,0 +1,13 @@ +using System.Linq.Expressions; +using HotChocolate.Resolvers; + +namespace HotChocolate.Types.Selections +{ + public interface IListHandler + { + Expression HandleLeave( + SelectionVisitorContext context, + IFieldSelection selection, + Expression expression); + } +} diff --git a/src/Core/Types.Selection/Handler/ListHandlers.cs b/src/Core/Types.Selection/Handler/ListHandlers.cs new file mode 100644 index 00000000000..c31a209343b --- /dev/null +++ b/src/Core/Types.Selection/Handler/ListHandlers.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace HotChocolate.Types.Selections +{ + internal static class ListHandlers + { + public static IReadOnlyList All { get; } = + new IListHandler[] + { + new FilterHandler(), + new SortHandler() + }; + } +} diff --git a/src/Core/Types.Selection/Handler/SortHandler.cs b/src/Core/Types.Selection/Handler/SortHandler.cs new file mode 100644 index 00000000000..06f9873235b --- /dev/null +++ b/src/Core/Types.Selection/Handler/SortHandler.cs @@ -0,0 +1,31 @@ +using System.Linq.Expressions; +using HotChocolate.Language; +using HotChocolate.Resolvers; +using HotChocolate.Types.Sorting; + +namespace HotChocolate.Types.Selections +{ + public class SortHandler : IListHandler + { + private const string ArgumentName = + SortObjectFieldDescriptorExtensions.OrderByArgumentName; + + public Expression HandleLeave( + SelectionVisitorContext context, + IFieldSelection selection, + Expression expression) + { + if (context.TryGetValueNode(ArgumentName, out IValueNode sortArgument) && + selection.Field.Arguments[ArgumentName].Type is InputObjectType iot && + iot is ISortInputType fit) + { + var visitor = new QueryableSortVisitor(iot, fit.EntityType); + + sortArgument.Accept(visitor); + return visitor.Compile(expression); + } + + return expression; + } + } +} diff --git a/src/Core/Types.Selection/SelectionClosure.cs b/src/Core/Types.Selection/SelectionClosure.cs new file mode 100644 index 00000000000..ce36733a7ae --- /dev/null +++ b/src/Core/Types.Selection/SelectionClosure.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace HotChocolate.Types.Selections +{ + public class SelectionClosure + { + public SelectionClosure(Type clrType, string parameterName) + { + if (parameterName == null) + { + throw new ArgumentNullException(nameof(parameterName)); + } + + ClrType = clrType ?? throw new ArgumentNullException(nameof(clrType)); + Parameter = Expression.Parameter(clrType, parameterName); + Instance = new Stack(); + Projections = new Dictionary(); + Instance.Push(Parameter); + } + + public Stack Instance { get; } + + public Type ClrType { get; } + + public ParameterExpression Parameter { get; } + + public Dictionary Projections { get; } + + public Expression CreateMemberInit() + { + NewExpression ctor = Expression.New(ClrType); + return Expression.MemberInit(ctor, Projections.Values); + } + + public Expression CreateMemberInitLambda() + { + return Expression.Lambda(CreateMemberInit(), Parameter); + } + + public Expression CreateSelection(Expression source, Type sourceType) + { + MethodCallExpression selection = Expression.Call( + typeof(Enumerable), + "Select", + new[] { ClrType, ClrType }, + source, + CreateMemberInitLambda()); + + if (sourceType.IsArray) + { + return ToArray(selection); + } + + if (TryGetSetType(sourceType, out Type setType)) + { + return ToSet(selection, setType); + } + + return ToList(selection); + } + + private Expression ToArray(Expression source) + { + return Expression.Call( + typeof(Enumerable), + "ToArray", + new[] { ClrType }, + source); + } + + private Expression ToList(Expression source) + { + return Expression.Call( + typeof(Enumerable), + "ToList", + new[] { ClrType }, + source); + } + + private Expression ToSet( + Expression source, + Type setType) + { + Type typedGeneric = + setType.MakeGenericType(source.Type.GetGenericArguments()[0]); + + ConstructorInfo ctor = + typedGeneric.GetConstructor(new[] { source.Type }); + + return Expression.New(ctor, source); + } + + private bool TryGetSetType( + Type type, out Type setType) + { + if (type.IsGenericType) + { + Type typeDefinition = type.GetGenericTypeDefinition(); + if (typeDefinition == typeof(ISet<>) + || typeDefinition == typeof(HashSet<>)) + { + setType = typeof(HashSet<>); + return true; + } + else if (typeDefinition == typeof(SortedSet<>)) + { + setType = typeof(SortedSet<>); + return true; + } + } + setType = null; + return false; + } + } +} diff --git a/src/Core/Types.Selection/SelectionMiddleware~1.cs b/src/Core/Types.Selection/SelectionMiddleware~1.cs new file mode 100644 index 00000000000..cb9d1dd6869 --- /dev/null +++ b/src/Core/Types.Selection/SelectionMiddleware~1.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using HotChocolate.Resolvers; +using HotChocolate.Types.Selections; +using HotChocolate.Utilities; + +namespace HotChocolate.Types +{ + public class SelectionMiddleware + { + private readonly FieldDelegate _next; + + private readonly ITypeConversion _converter; + public SelectionMiddleware( + FieldDelegate next, + ITypeConversion converter) + { + _next = next ?? throw new ArgumentNullException(nameof(next)); + _converter = converter ?? TypeConversion.Default; + } + + public async Task InvokeAsync(IMiddlewareContext context) + { + await _next(context).ConfigureAwait(false); + + IQueryable source = null; + + if (context.Result is IQueryable q) + { + source = q; + } + else if (context.Result is IEnumerable e) + { + source = e.AsQueryable(); + } + + var visitor = new SelectionVisitor(context, _converter); + visitor.Accept(context.Field); + context.Result = source.Select(visitor.Project()); + } + } +} diff --git a/src/Core/Types.Selection/SelectionVisitor.cs b/src/Core/Types.Selection/SelectionVisitor.cs new file mode 100644 index 00000000000..1eea7945563 --- /dev/null +++ b/src/Core/Types.Selection/SelectionVisitor.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; +using HotChocolate.Execution; +using HotChocolate.Language; +using HotChocolate.Resolvers; +using HotChocolate.Utilities; + +namespace HotChocolate.Types.Selections +{ + public class SelectionVisitor + : SelectionVisitorBase + { + private readonly ITypeConversion _converter; + private readonly IReadOnlyList _listHandler = ListHandlers.All; + + public SelectionVisitor( + IResolverContext context, + ITypeConversion converter) + : base(context) + { + _converter = converter; + } + + protected Stack Closures { get; } = + new Stack(); + + public void Accept(ObjectField field) + { + IOutputType type = field.Type; + SelectionSetNode selectionSet = Context.FieldSelection.SelectionSet; + (type, selectionSet) = UnwrapPaging(type, selectionSet); + IType elementType = type.IsListType() ? type.ElementType() : type; + Closures.Push(new SelectionClosure(elementType.ToClrType(), "e")); + VisitSelections(type, selectionSet); + } + + public Expression> Project() + { + return (Expression>)Closures.Peek().CreateMemberInitLambda(); + } + + protected override void LeaveLeaf(IFieldSelection selection) + { + if (selection.Field.Member is PropertyInfo member) + { + SelectionClosure closure = Closures.Peek(); + + closure.Projections[member.Name] = Expression.Bind( + member, Expression.Property(closure.Instance.Peek(), member)); + } + base.LeaveLeaf(selection); + } + + protected override void LeaveObject(IFieldSelection selection) + { + if (selection.Field.Member is PropertyInfo) + { + Expression memberInit = Closures.Pop().CreateMemberInit(); + + Closures.Peek().Projections[selection.Field.Name] = + Expression.Bind(selection.Field.Member, memberInit); + + base.LeaveObject(selection); + } + else + { + throw new QueryException( + ErrorBuilder.New() + .SetMessage( + string.Format( + "UseSelection is in a invalid state. Field {0}" + + " should never have been visited!", + selection.Field.Name)) + .Build()); + } + } + + protected override void LeaveList(IFieldSelection selection) + { + if (selection.Field.Member is PropertyInfo propertyInfo) + { + SelectionClosure closure = Closures.Pop(); + + Expression body = + Expression.Property( + Closures.Peek().Instance.Peek(), propertyInfo); + + if (selection is FieldSelection fieldSelection) + { + var context = + new SelectionVisitorContext(Context, _converter, fieldSelection); + + for (var i = 0; i < _listHandler.Count; i++) + { + body = _listHandler[i].HandleLeave(context, selection, body); + } + } + + Expression select = + closure.CreateSelection(body, propertyInfo.PropertyType); + + Closures.Peek().Projections[selection.Field.Name] = + Expression.Bind(selection.Field.Member, select); + + base.LeaveList(selection); + } + else + { + throw new QueryException( + ErrorBuilder.New() + .SetMessage( + string.Format( + "UseSelection is in a invalid state. Field {0}" + + " should never have been visited!", + selection.Field.Name)) + .Build()); + } + } + + protected override void EnterList(IFieldSelection selection) + { + if (selection.Field.Member is PropertyInfo) + { + (IOutputType type, SelectionSetNode selectionSet) = + UnwrapPaging(selection.Field.Type, selection.Selection.SelectionSet); + + Closures.Push( + new SelectionClosure( + type.ElementType().ToClrType(), + "e" + Closures.Count)); + + VisitSelections(type, selectionSet); + } + } + + protected override void EnterObject(IFieldSelection selection) + { + if (selection.Field.Member is PropertyInfo property) + { + var nextClosure = + new SelectionClosure( + selection.Field.ClrType, "e" + Closures.Count); + + nextClosure.Instance.Push( + Expression.Property( + Closures.Peek().Instance.Peek(), property)); + + Closures.Push(nextClosure); + base.EnterObject(selection); + } + } + } +} diff --git a/src/Core/Types.Selection/SelectionVisitorBase.cs b/src/Core/Types.Selection/SelectionVisitorBase.cs new file mode 100644 index 00000000000..4b05cb62d4e --- /dev/null +++ b/src/Core/Types.Selection/SelectionVisitorBase.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using HotChocolate.Execution; +using HotChocolate.Language; +using HotChocolate.Resolvers; +using HotChocolate.Types.Relay; + +namespace HotChocolate.Types.Selections +{ + public class SelectionVisitorBase + { + protected SelectionVisitorBase( + IResolverContext context) + { + Context = context + ?? throw new ArgumentNullException(nameof(context)); + } + + protected Stack Fields { get; } = + new Stack(); + + protected readonly IResolverContext Context; + + protected virtual void VisitSelections( + IOutputType outputType, + SelectionSetNode selectionSet) + { + (outputType, selectionSet) = UnwrapPaging(outputType, selectionSet); + if (outputType.NamedType() is ObjectType type) + { + foreach (IFieldSelection selection in Context.CollectFields(type, selectionSet)) + { + EnterSelection(selection); + LeaveSelection(selection); + } + } + else + { + throw new QueryException( + ErrorBuilder.New() + .SetMessage( + string.Format( + "UseSelection is in a invalid state. Type {0} " + + "is illegal!", + outputType.NamedType().Name)) + .Build()); + } + } + + protected virtual void LeaveSelection(IFieldSelection selection) + { + Fields.Pop(); + } + + protected virtual void EnterSelection(IFieldSelection selection) + { + Fields.Push(selection.Field); + if (selection.Field.Type.IsListType() || + selection.Field.Type.ToClrType() == typeof(IConnection)) + { + EnterList(selection); + LeaveList(selection); + } + else if (selection.Field.Type.IsLeafType()) + { + EnterLeaf(selection); + LeaveLeaf(selection); + } + else if (selection.Field.Type.IsObjectType()) + { + EnterObject(selection); + LeaveObject(selection); + } + else + { + throw new QueryException( + ErrorBuilder.New() + .SetMessage( + string.Format( + "UseSelection is in a invalid state. Type {0} " + + "is illegal!", + selection.Field.Type.NamedType().Name)) + .Build()); + } + } + + protected virtual void EnterList(IFieldSelection selection) + { + (IOutputType type, SelectionSetNode selectionSet) = + UnwrapPaging(selection.Field.Type, selection.Selection.SelectionSet); + VisitSelections(type, selectionSet); + } + + protected virtual void LeaveList(IFieldSelection selection) + { + } + + protected virtual void EnterLeaf(IFieldSelection selection) + { + } + + protected virtual void LeaveLeaf(IFieldSelection selection) + { + } + + protected virtual void EnterObject(IFieldSelection selection) + { + VisitSelections(selection.Field.Type, selection.Selection.SelectionSet); + } + + protected virtual void LeaveObject(IFieldSelection selection) + { + } + + protected (IOutputType, SelectionSetNode) UnwrapPaging( + IOutputType outputType, + SelectionSetNode selectionSet) + { + if (TryUnwrapPaging( + outputType, + selectionSet, + out (IOutputType, SelectionSetNode) result)) + { + return result; + } + return (outputType, selectionSet); + } + + private bool TryUnwrapPaging( + IOutputType outputType, + SelectionSetNode selectionSet, + out (IOutputType, SelectionSetNode) result) + { + result = (null, null); + + if (outputType.ToClrType() == typeof(IConnection) && + outputType.NamedType() is ObjectType type) + { + foreach (IFieldSelection selection in Context.CollectFields(type, selectionSet)) + { + IFieldSelection currentSelection = GetPagingFieldOrDefault(selection); + + if (currentSelection != null) + { + result = MergeSelection(result.Item2, currentSelection); + } + } + } + return result.Item2 != null; + } + + private IFieldSelection GetPagingFieldOrDefault(IFieldSelection selection) + { + if (selection.Field.Name == "nodes") + { + return selection; + } + else if (selection.Field.Name == "edges" && + selection.Field.Type.NamedType() is ObjectType edgeType) + { + return Context + .CollectFields(edgeType, selection.Selection.SelectionSet) + .FirstOrDefault(x => x.Field.Name == "node"); + } + return null; + } + + private (IOutputType, SelectionSetNode) MergeSelection( + SelectionSetNode selectionSet, + IFieldSelection selection) + { + if (selectionSet == null) + { + selectionSet = selection.Selection.SelectionSet; + } + else + { + selectionSet = selectionSet.WithSelections( + selectionSet.Selections.Concat( + selection.Selection.SelectionSet.Selections) + .ToList()); + } + return (selection.Field.Type, selectionSet); + } + } +} diff --git a/src/Core/Types.Selection/SelectionVisitorContext.cs b/src/Core/Types.Selection/SelectionVisitorContext.cs new file mode 100644 index 00000000000..22708eab55f --- /dev/null +++ b/src/Core/Types.Selection/SelectionVisitorContext.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using HotChocolate.Execution; +using HotChocolate.Language; +using HotChocolate.Resolvers; +using HotChocolate.Utilities; + +namespace HotChocolate.Types.Selections +{ + public class SelectionVisitorContext + { + private readonly IReadOnlyDictionary _arguments; + private readonly IResolverContext _context; + + public SelectionVisitorContext( + IResolverContext context, + ITypeConversion conversion, + FieldSelection fieldSelection) + { + Conversion = conversion; + _context = context; + _arguments = fieldSelection.CoerceArguments(context.Variables, conversion); + } + + public ITypeConversion Conversion { get; } + + public bool TryGetValueNode(string key, out IValueNode arg) + { + if (_arguments.TryGetValue(key, out ArgumentValue argumentValue) && + argumentValue.Literal != null && + !(argumentValue.Literal is NullValueNode)) + { + EnsureNoError(argumentValue); + + IValueNode literal = argumentValue.Literal; + + arg = VariableToValueRewriter.Rewrite( + literal, + argumentValue.Type, + _context.Variables, Conversion); + + return true; + } + arg = null; + return false; + } + + protected void EnsureNoError(ArgumentValue argumentValue) + { + if (argumentValue.Error != null) + { + throw new QueryException(argumentValue.Error); + } + } + } +} diff --git a/src/Core/Types.Selection/Types.Selection.csproj b/src/Core/Types.Selection/Types.Selection.csproj new file mode 100644 index 00000000000..90d24d19769 --- /dev/null +++ b/src/Core/Types.Selection/Types.Selection.csproj @@ -0,0 +1,26 @@ + + + + $(MSBuildThisFileDirectory.TrimEnd('\').TrimEnd('/')) + $([System.IO.Path]::Combine($(ChilliCurrentDirectory), '..', '..', '..', 'tools')) + $([System.IO.Path]::Combine($(ChilliImport), 'CoreFramework.props')) + $([System.IO.Path]::Combine($(ChilliImport), 'BuildSettings.props')) + + + + + + + HotChocolate.Types.Selections + HotChocolate.Types.Selections + HotChocolate.Types.Selections + + + + + + + + + + diff --git a/src/Core/Types.Selection/UseSelectionAttribute.cs b/src/Core/Types.Selection/UseSelectionAttribute.cs new file mode 100644 index 00000000000..a992af9d8e3 --- /dev/null +++ b/src/Core/Types.Selection/UseSelectionAttribute.cs @@ -0,0 +1,16 @@ +using System.Reflection; +using HotChocolate.Types.Descriptors; + +namespace HotChocolate.Types +{ + public sealed class UseSelectionAttribute : ObjectFieldDescriptorAttribute + { + public override void OnConfigure( + IDescriptorContext context, + IObjectFieldDescriptor descriptor, + MemberInfo member) + { + descriptor.UseSelection(); + } + } +} diff --git a/src/Core/Types.Sorting.Mongo.Tests/MongoSortingTests.cs b/src/Core/Types.Sorting.Mongo.Tests/MongoSortingTests.cs index 1458fb51bfc..28051d048df 100644 --- a/src/Core/Types.Sorting.Mongo.Tests/MongoSortingTests.cs +++ b/src/Core/Types.Sorting.Mongo.Tests/MongoSortingTests.cs @@ -1,12 +1,12 @@ -using MongoDB.Driver; -using MongoDB.Bson; -using Microsoft.Extensions.DependencyInjection; -using HotChocolate.Execution; -using Xunit; using System.Threading.Tasks; -using Snapshooter.Xunit; +using HotChocolate.Execution; using HotChocolate.Types.Relay; +using Microsoft.Extensions.DependencyInjection; +using MongoDB.Bson; +using MongoDB.Driver; +using Snapshooter.Xunit; using Squadron; +using Xunit; namespace HotChocolate.Types.Sorting { diff --git a/src/Core/Types.Sorting.Mongo.Tests/Types.Sorting.Mongo.Tests.csproj b/src/Core/Types.Sorting.Mongo.Tests/Types.Sorting.Mongo.Tests.csproj index 453893f2732..ba12094fe66 100644 --- a/src/Core/Types.Sorting.Mongo.Tests/Types.Sorting.Mongo.Tests.csproj +++ b/src/Core/Types.Sorting.Mongo.Tests/Types.Sorting.Mongo.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/src/Core/Types.Sorting.Tests/QueryableExtensionsTests.cs b/src/Core/Types.Sorting.Tests/QueryableExtensionsTests.cs index 04985a2c543..069e239cd11 100644 --- a/src/Core/Types.Sorting.Tests/QueryableExtensionsTests.cs +++ b/src/Core/Types.Sorting.Tests/QueryableExtensionsTests.cs @@ -7,7 +7,7 @@ namespace HotChocolate.Types.Sorting public class QueryableExtensionsTests { [Fact] - public void AddInitialSortOperation_AscOnIQueryable_ShouldAddOrderBy() + public void CompileInitialSortOperation_AscOnIQueryable_ShouldAddOrderBy() { // arrange IQueryable source = new Foo[0].AsQueryable(); @@ -17,17 +17,19 @@ public void AddInitialSortOperation_AscOnIQueryable_ShouldAddOrderBy() ParameterExpression parameter = Expression.Parameter(typeof(Foo)); // act - IOrderedQueryable sorted = source.AddInitialSortOperation( + Expression sortExpression = source.Expression.CompileInitialSortOperation( operation, parameter ); + IQueryable sorted = + source.Provider.CreateQuery(sortExpression); // assert Assert.Equal(source.OrderBy(s => s.Bar), sorted); } [Fact] - public void AddInitialSortOperation_DescOnIQueryable_ShouldAddOrderBy() + public void CompileInitialSortOperation_DescOnIQueryable_ShouldAddOrderBy() { // arrange IQueryable source = new Foo[0].AsQueryable(); @@ -37,17 +39,19 @@ public void AddInitialSortOperation_DescOnIQueryable_ShouldAddOrderBy() ParameterExpression parameter = Expression.Parameter(typeof(Foo)); // act - IOrderedQueryable sorted = source.AddInitialSortOperation( + Expression sortExpression = source.Expression.CompileInitialSortOperation( operation, parameter ); + IQueryable sorted = + source.Provider.CreateQuery(sortExpression); // assert Assert.Equal(source.OrderByDescending(s => s.Bar), sorted); } [Fact] - public void AddSortOperation_AscOnIOrderedQueryable_ShouldAddThenBy() + public void CompileSortOperation_AscOnIOrderedQueryable_ShouldAddThenBy() { // arrange IOrderedQueryable source = new Foo[0].AsQueryable().OrderBy(f => f.Bar); @@ -57,17 +61,20 @@ public void AddSortOperation_AscOnIOrderedQueryable_ShouldAddThenBy() ParameterExpression parameter = Expression.Parameter(typeof(Foo)); // act - IOrderedQueryable sorted = source.AddInitialSortOperation( + Expression sortExpression = source.Expression.CompileSortOperation( operation, parameter ); + IQueryable sorted = + source.Provider.CreateQuery(sortExpression); + // assert Assert.Equal(source.ThenBy(s => s.Bar), sorted); } [Fact] - public void AddSortOperation_DescOnIOrderedQueryable_ShouldAddThenByDescending() + public void CompileSortOperation_DescOnIOrderedQueryable_ShouldAddThenByDescending() { // arrange IOrderedQueryable source = new Foo[0].AsQueryable().OrderBy(f => f.Bar); @@ -77,10 +84,12 @@ public void AddSortOperation_DescOnIOrderedQueryable_ShouldAddThenByDescending() ParameterExpression parameter = Expression.Parameter(typeof(Foo)); // act - IOrderedQueryable sorted = source.AddInitialSortOperation( + Expression sortExpression = source.Expression.CompileSortOperation( operation, parameter ); + IQueryable sorted = + source.Provider.CreateQuery(sortExpression); // assert Assert.Equal(source.ThenByDescending(s => s.Bar), sorted); diff --git a/src/Core/Types.Sorting/Extensions/SortObjectFieldDescriptorExtensions.cs b/src/Core/Types.Sorting/Extensions/SortObjectFieldDescriptorExtensions.cs index 9b2df94c136..99dcef4d713 100644 --- a/src/Core/Types.Sorting/Extensions/SortObjectFieldDescriptorExtensions.cs +++ b/src/Core/Types.Sorting/Extensions/SortObjectFieldDescriptorExtensions.cs @@ -11,7 +11,7 @@ namespace HotChocolate.Types { public static class SortObjectFieldDescriptorExtensions { - internal const string OrderByArgumentName = "order_by"; + public const string OrderByArgumentName = "order_by"; private static readonly Type _middlewareDefinition = typeof(QueryableSortMiddleware<>); diff --git a/src/Core/Types.Sorting/QueryableExtensions.cs b/src/Core/Types.Sorting/QueryableExtensions.cs index 61a63dc7b09..3b526b72699 100644 --- a/src/Core/Types.Sorting/QueryableExtensions.cs +++ b/src/Core/Types.Sorting/QueryableExtensions.cs @@ -7,36 +7,69 @@ namespace HotChocolate.Types.Sorting { internal static class QueryableExtensions { - internal static IOrderedQueryable AddInitialSortOperation( - this IQueryable source, + internal static Expression CompileInitialSortOperation( + this Expression source, SortOperationInvocation operation, ParameterExpression parameter) { - Expression> lambda - = HandleProperty(operation, parameter); + Expression lambda + = HandleProperty(operation, parameter); + + Type type = typeof(Enumerable); + if (typeof(IOrderedQueryable).IsAssignableFrom(source.Type) || + typeof(IQueryable).IsAssignableFrom(source.Type)) + { + type = typeof(Queryable); + } if (operation.Kind == SortOperationKind.Desc) { - return source.OrderByDescending(lambda); + return Expression.Call( + type, + "OrderByDescending", + new[] { operation.Property.DeclaringType, operation.Property.PropertyType }, + source, + lambda); } - return source.OrderBy(lambda); + return Expression.Call( + type, + "OrderBy", + new[] { operation.Property.DeclaringType, operation.Property.PropertyType }, + source, + lambda); } - internal static IOrderedQueryable AddSortOperation( - this IOrderedQueryable source, + internal static Expression CompileSortOperation( + this Expression source, SortOperationInvocation operation, ParameterExpression parameter) { - Expression> lambda - = HandleProperty(operation, parameter); + Expression lambda + = HandleProperty(operation, parameter); + + Type type = typeof(Enumerable); + if (typeof(IOrderedQueryable).IsAssignableFrom(source.Type)) + { + type = typeof(Queryable); + } if (operation.Kind == SortOperationKind.Desc) { - return source.ThenByDescending(lambda); + return Expression.Call( + type, + "ThenByDescending", + new[] { operation.Property.DeclaringType, operation.Property.PropertyType }, + source, + lambda); } - return source.ThenBy(lambda); + return Expression.Call( + type, + "ThenBy", + new[] { operation.Property.DeclaringType, operation.Property.PropertyType }, + source, + lambda); } internal static Expression> HandleProperty( @@ -48,5 +81,14 @@ internal static Expression> HandleProperty( UnaryExpression propAsObject = Expression.Convert(property, typeof(object)); return Expression.Lambda>(propAsObject, parameter); } + + internal static Expression HandleProperty( + SortOperationInvocation operation, ParameterExpression parameter) + { + PropertyInfo propertyInfo = operation.Property; + + MemberExpression property = Expression.Property(parameter, propertyInfo); + return Expression.Lambda(property, parameter); + } } } diff --git a/src/Core/Types.Sorting/QueryableSortVisitor.cs b/src/Core/Types.Sorting/QueryableSortVisitor.cs index 650e2b0a5ea..4635f36e6ad 100644 --- a/src/Core/Types.Sorting/QueryableSortVisitor.cs +++ b/src/Core/Types.Sorting/QueryableSortVisitor.cs @@ -33,30 +33,34 @@ public QueryableSortVisitor( public IQueryable Sort( IQueryable source) { - if (!Instance.Any()) + if (Instance.Count == 0) { return source; } + return source.Provider.CreateQuery(Compile(source.Expression)); + } - IOrderedQueryable sortedSource; - if (!OrderingMethodFinder.OrderMethodExists(source.Expression)) + public Expression Compile( + Expression source) + { + if (Instance.Count == 0) { - sortedSource = source.AddInitialSortOperation( - Instance.Dequeue(), _parameter); + return source; } - else + + if (!OrderingMethodFinder.OrderMethodExists(source)) { - sortedSource = (IOrderedQueryable)source; + source = source.CompileInitialSortOperation( + Instance.Dequeue(), _parameter); } - while (Instance.Any()) + while (Instance.Count != 0) { - sortedSource - = sortedSource.AddSortOperation( + source = source.CompileSortOperation( Instance.Dequeue(), _parameter); } - return sortedSource; + return source; } #region Object Value diff --git a/src/Core/Types.Tests/Resolvers/ParentAttributeTest.cs b/src/Core/Types.Tests/Resolvers/ParentAttributeTest.cs new file mode 100644 index 00000000000..20e2eb8161c --- /dev/null +++ b/src/Core/Types.Tests/Resolvers/ParentAttributeTest.cs @@ -0,0 +1,124 @@ +using System.Threading.Tasks; +using HotChocolate.Execution; +using HotChocolate.Types; +using Xunit; + +namespace HotChocolate.Resolvers +{ + public class ParentAttributeTest + { + [Fact] + public async Task GenericObjectType_ParentResolver_BindsParentCorrectly() + { + // arrange + var objectType = new ObjectType( + t => t.Field(f => f.GetParent(default)).Name("desc")); + var schema = Schema.Create(t => t.RegisterQueryType(objectType)); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery("{ desc }") + .SetInitialValue(new Foo()) + .Create()); + + // assert + var queryResult = result as ReadOnlyQueryResult; + Assert.NotNull(queryResult); + Assert.Empty(queryResult.Errors); + Assert.Equal("hello", queryResult.Data["desc"]); + } + + [Fact] + public async Task ObjectType_ParentResolver_BindsParentCorrectly() + { + // arrange + var objectType = new ObjectType(t => t.Name("Bar") + .Field(f => f.GetParent(default)) + .Name("desc") + .Type()); + var schema = Schema.Create(t => t.RegisterQueryType(objectType)); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery("{ desc }") + .SetInitialValue(new Foo()) + .Create()); + + // assert + var queryResult = result as ReadOnlyQueryResult; + Assert.NotNull(queryResult); + Assert.Empty(queryResult.Errors); + Assert.Equal("hello", queryResult.Data["desc"]); + } + + [Fact] + public async Task ExternalResolver_ParentProperty_BindsPropertyCorrectly() + { + // arrange + var schema = Schema.Create( + t => t.RegisterQueryType().RegisterType()); + IQueryExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery("{ description }") + .SetInitialValue(new Foo()) + .Create()); + + // assert + var queryResult = result as ReadOnlyQueryResult; + Assert.NotNull(queryResult); + Assert.Empty(queryResult.Errors); + Assert.Equal("hellocustom", queryResult.Data["description"]); + } + + public class Foo + { + public Bar Bar { get; } = new Bar(); + public string Description { get; } = "hello"; + } + + public class FooCollision + { + public static FooCollision _val = new FooCollision(); + public FooCollision Recursive { get; } = _val; + public string Description { get; set; } = "hello"; + } + + public class Bar : IBar + { + public string Description { get; } = "nested"; + } + + public interface IBar + { + string Description { get; } + } + + public class FooResolver + { + public string GetParent([Parent]Foo foo) => foo.Description; + public string GetPure() => "foo"; + } + + [ExtendObjectType(Name = "Foo")] + public class FooExtension + { + public string GetPure() => "foo"; + public string GetParent([Parent]Foo foo) => foo.Description; + } + + [GraphQLResolverOf("Foo")] + public class FooWorkingResolvers + { + public string GetDescription([Parent]Foo foo) => foo.Description + "custom"; + public string GetPure() => "foo"; + } + + } +} diff --git a/src/Core/Types/Configuration/RegisteredResolver.cs b/src/Core/Types/Configuration/RegisteredResolver.cs index 84dda6542ff..3537f6e14ae 100644 --- a/src/Core/Types/Configuration/RegisteredResolver.cs +++ b/src/Core/Types/Configuration/RegisteredResolver.cs @@ -44,5 +44,17 @@ public RegisteredResolver WithField(IFieldReference field) ResolverType, SourceType, field); } + + public RegisteredResolver WithSourceType(Type sourceType) + { + if (sourceType == null) + { + throw new ArgumentNullException(nameof(sourceType)); + } + + return new RegisteredResolver( + ResolverType, sourceType, + Field); + } } } diff --git a/src/Core/Types/Configuration/TypeInitializer.cs b/src/Core/Types/Configuration/TypeInitializer.cs index 48fabaaf43d..f2d3c7cb4eb 100644 --- a/src/Core/Types/Configuration/TypeInitializer.cs +++ b/src/Core/Types/Configuration/TypeInitializer.cs @@ -224,6 +224,13 @@ private void MergeTypeExtension( .Build()); } + InitializationContext initContext = extension.InitializationContext; + foreach (FieldReference reference in initContext.Resolvers.Keys) + { + _resolvers[reference] + = initContext.Resolvers[reference].WithSourceType(type.ClrType); + } + // merge CompletionContext context = _completionContext[extension]; context.Status = TypeStatus.Named; @@ -330,8 +337,9 @@ private static bool IsResolverRelevant( { ParameterInfo parent = m.GetParameters() .FirstOrDefault(t => t.IsDefined(typeof(ParentAttribute))); - return parent == null - || parent.ParameterType.IsAssignableFrom(sourceType); + + return parent == null || + parent.ParameterType.IsAssignableFrom(sourceType); } return false; diff --git a/src/Core/Types/Properties/TypeResources.Designer.cs b/src/Core/Types/Properties/TypeResources.Designer.cs index 1b16675e7c2..77e7b21b747 100644 --- a/src/Core/Types/Properties/TypeResources.Designer.cs +++ b/src/Core/Types/Properties/TypeResources.Designer.cs @@ -8,11 +8,10 @@ // //------------------------------------------------------------------------------ -namespace HotChocolate.Properties -{ +namespace HotChocolate.Properties { using System; - - + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -23,1736 +22,1458 @@ namespace HotChocolate.Properties [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class TypeResources - { - + internal class TypeResources { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal TypeResources() - { + internal TypeResources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if (object.ReferenceEquals(resourceMan, null)) - { + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HotChocolate.Properties.TypeResources", typeof(TypeResources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { + internal static global::System.Globalization.CultureInfo Culture { + get { return resourceCulture; } - set - { + set { resourceCulture = value; } } - + /// /// Looks up a localized string similar to The argument `{0}` has no type. Specify the type with `.Argument("{0}", a.Type<MyType>())` to fix this issue.. /// - internal static string Argument_TypeIsNull - { - get - { + internal static string Argument_TypeIsNull { + get { return ResourceManager.GetString("Argument_TypeIsNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The argument type has to be an input-type.. /// - internal static string ArgumentDescriptor_InputTypeViolation - { - get - { + internal static string ArgumentDescriptor_InputTypeViolation { + get { return ResourceManager.GetString("ArgumentDescriptor_InputTypeViolation", resourceCulture); } } - + /// /// Looks up a localized string similar to Argument `{0}` of non-null type `{1}` must not be null.. /// - internal static string ArgumentValueBuilder_NonNull - { - get - { + internal static string ArgumentValueBuilder_NonNull { + get { return ResourceManager.GetString("ArgumentValueBuilder_NonNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The `Boolean` scalar type represents `true` or `false`.. /// - internal static string BooleanType_Description - { - get - { + internal static string BooleanType_Description { + get { return ResourceManager.GetString("BooleanType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The `Byte` scalar type represents non-fractional whole numeric values. Byte can represent values between 0 and 255.. /// - internal static string ByteType_Description - { - get - { + internal static string ByteType_Description { + get { return ResourceManager.GetString("ByteType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to Only type system objects are allowed.. /// - internal static string ClrTypeReference_OnlyTsosAreAllowed - { - get - { + internal static string ClrTypeReference_OnlyTsosAreAllowed { + get { return ResourceManager.GetString("ClrTypeReference_OnlyTsosAreAllowed", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified IComplexTypeFieldBindingBuilder-implementation is not supported.. /// - internal static string ComplexTypeBindingBuilder_FieldBuilderNotSupported - { - get - { + internal static string ComplexTypeBindingBuilder_FieldBuilderNotSupported { + get { return ResourceManager.GetString("ComplexTypeBindingBuilder_FieldBuilderNotSupported", resourceCulture); } } - + /// /// Looks up a localized string similar to The field binding builder is not completed and cannot be added.. /// - internal static string ComplexTypeBindingBuilder_FieldNotComplete - { - get - { + internal static string ComplexTypeBindingBuilder_FieldNotComplete { + get { return ResourceManager.GetString("ComplexTypeBindingBuilder_FieldNotComplete", resourceCulture); } } - + /// /// Looks up a localized string similar to The DataLoader key cannot be null or empty.. /// - internal static string DataLoaderRegistry_KeyNullOrEmpty - { - get - { + internal static string DataLoaderRegistry_KeyNullOrEmpty { + get { return ResourceManager.GetString("DataLoaderRegistry_KeyNullOrEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to No DataLoader registry was registerd with your dependency injection.. /// - internal static string DataLoaderResolverContextExtensions_RegistryIsNull - { - get - { + internal static string DataLoaderResolverContextExtensions_RegistryIsNull { + get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_RegistryIsNull", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to register a DataLoader with your DataLoader registry.. /// - internal static string DataLoaderResolverContextExtensions_UnableToRegister - { - get - { + internal static string DataLoaderResolverContextExtensions_UnableToRegister { + get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_UnableToRegister", resourceCulture); } } - + /// /// Looks up a localized string similar to The `DateTime` scalar represents an ISO-8601 compliant date time type.. /// - internal static string DateTimeType_Description - { - get - { + internal static string DateTimeType_Description { + get { return ResourceManager.GetString("DateTimeType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The `Date` scalar represents an ISO-8601 compliant date type.. /// - internal static string DateType_Description - { - get - { + internal static string DateType_Description { + get { return ResourceManager.GetString("DateType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The built-in `Decimal` scalar type.. /// - internal static string DecimalType_Description - { - get - { + internal static string DecimalType_Description { + get { return ResourceManager.GetString("DecimalType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified member has to be a method or a property.. /// - internal static string DefaultTypeInspector_MemberInvalid - { - get - { + internal static string DefaultTypeInspector_MemberInvalid { + get { return ResourceManager.GetString("DefaultTypeInspector_MemberInvalid", resourceCulture); } } - + /// /// Looks up a localized string similar to Only type system objects are allowed as schema type.. /// - internal static string DependencyDescriptorBase_OnlyTsoIsAllowed - { - get - { + internal static string DependencyDescriptorBase_OnlyTsoIsAllowed { + get { return ResourceManager.GetString("DependencyDescriptorBase_OnlyTsoIsAllowed", resourceCulture); } } - + /// /// Looks up a localized string similar to A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. /// ///In some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.. /// - internal static string Directive_Description - { - get - { + internal static string Directive_Description { + get { return ResourceManager.GetString("Directive_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to Use `locations`.. /// - internal static string Directive_UseLocation - { - get - { + internal static string Directive_UseLocation { + get { return ResourceManager.GetString("Directive_UseLocation", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified directive `@{0}` is unique and cannot be added twice.. /// - internal static string DirectiveCollection_DirectiveIsUnique - { - get - { + internal static string DirectiveCollection_DirectiveIsUnique { + get { return ResourceManager.GetString("DirectiveCollection_DirectiveIsUnique", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified directive `@{0}` is not allowed on the current location `{1}`.. /// - internal static string DirectiveCollection_LocationNotAllowed - { - get - { + internal static string DirectiveCollection_LocationNotAllowed { + get { return ResourceManager.GetString("DirectiveCollection_LocationNotAllowed", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to an argument definition. /// - internal static string DirectiveLocation_ArgumentDefinition - { - get - { + internal static string DirectiveLocation_ArgumentDefinition { + get { return ResourceManager.GetString("DirectiveLocation_ArgumentDefinition", resourceCulture); } } - + /// /// Looks up a localized string similar to A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.. /// - internal static string DirectiveLocation_Description - { - get - { + internal static string DirectiveLocation_Description { + get { return ResourceManager.GetString("DirectiveLocation_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to an enum definition.. /// - internal static string DirectiveLocation_Enum - { - get - { + internal static string DirectiveLocation_Enum { + get { return ResourceManager.GetString("DirectiveLocation_Enum", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to an enum value definition.. /// - internal static string DirectiveLocation_EnumValue - { - get - { + internal static string DirectiveLocation_EnumValue { + get { return ResourceManager.GetString("DirectiveLocation_EnumValue", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to a field.. /// - internal static string DirectiveLocation_Field - { - get - { + internal static string DirectiveLocation_Field { + get { return ResourceManager.GetString("DirectiveLocation_Field", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to a field definition.. /// - internal static string DirectiveLocation_FieldDefinition - { - get - { + internal static string DirectiveLocation_FieldDefinition { + get { return ResourceManager.GetString("DirectiveLocation_FieldDefinition", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to a fragment definition.. /// - internal static string DirectiveLocation_FragmentDefinition - { - get - { + internal static string DirectiveLocation_FragmentDefinition { + get { return ResourceManager.GetString("DirectiveLocation_FragmentDefinition", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to a fragment spread.. /// - internal static string DirectiveLocation_FragmentSpread - { - get - { + internal static string DirectiveLocation_FragmentSpread { + get { return ResourceManager.GetString("DirectiveLocation_FragmentSpread", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to an inline fragment.. /// - internal static string DirectiveLocation_InlineFragment - { - get - { + internal static string DirectiveLocation_InlineFragment { + get { return ResourceManager.GetString("DirectiveLocation_InlineFragment", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to an input object field definition.. /// - internal static string DirectiveLocation_InputFieldDefinition - { - get - { + internal static string DirectiveLocation_InputFieldDefinition { + get { return ResourceManager.GetString("DirectiveLocation_InputFieldDefinition", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to an input object type definition.. /// - internal static string DirectiveLocation_InputObject - { - get - { + internal static string DirectiveLocation_InputObject { + get { return ResourceManager.GetString("DirectiveLocation_InputObject", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to an interface definition.. /// - internal static string DirectiveLocation_Interface - { - get - { + internal static string DirectiveLocation_Interface { + get { return ResourceManager.GetString("DirectiveLocation_Interface", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to a mutation operation.. /// - internal static string DirectiveLocation_Mutation - { - get - { + internal static string DirectiveLocation_Mutation { + get { return ResourceManager.GetString("DirectiveLocation_Mutation", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to an object type definition.. /// - internal static string DirectiveLocation_Object - { - get - { + internal static string DirectiveLocation_Object { + get { return ResourceManager.GetString("DirectiveLocation_Object", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to a query operation.. /// - internal static string DirectiveLocation_Query - { - get - { + internal static string DirectiveLocation_Query { + get { return ResourceManager.GetString("DirectiveLocation_Query", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to a scalar definition.. /// - internal static string DirectiveLocation_Scalar - { - get - { + internal static string DirectiveLocation_Scalar { + get { return ResourceManager.GetString("DirectiveLocation_Scalar", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to a schema definition.. /// - internal static string DirectiveLocation_Schema - { - get - { + internal static string DirectiveLocation_Schema { + get { return ResourceManager.GetString("DirectiveLocation_Schema", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to a subscription operation.. /// - internal static string DirectiveLocation_Subscription - { - get - { + internal static string DirectiveLocation_Subscription { + get { return ResourceManager.GetString("DirectiveLocation_Subscription", resourceCulture); } } - + /// /// Looks up a localized string similar to Location adjacent to a union definition.. /// - internal static string DirectiveLocation_Union - { - get - { + internal static string DirectiveLocation_Union { + get { return ResourceManager.GetString("DirectiveLocation_Union", resourceCulture); } } - + /// /// Looks up a localized string similar to The `{0}` directive does not declare any location on which it is valid.. /// - internal static string DirectiveType_NoLocations - { - get - { + internal static string DirectiveType_NoLocations { + get { return ResourceManager.GetString("DirectiveType_NoLocations", resourceCulture); } } - + /// /// Looks up a localized string similar to Replace Middleware with `Use`.. /// - internal static string DirectiveType_ReplaceWithUse - { - get - { + internal static string DirectiveType_ReplaceWithUse { + get { return ResourceManager.GetString("DirectiveType_ReplaceWithUse", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to convert the argument value to the specified type.. /// - internal static string DirectiveType_UnableToConvert - { - get - { + internal static string DirectiveType_UnableToConvert { + get { return ResourceManager.GetString("DirectiveType_UnableToConvert", resourceCulture); } } - + /// /// Looks up a localized string similar to Only property expressions are allowed to describe a directive type argument.. /// - internal static string DirectiveTypeDescriptor_OnlyProperties - { - get - { + internal static string DirectiveTypeDescriptor_OnlyProperties { + get { return ResourceManager.GetString("DirectiveTypeDescriptor_OnlyProperties", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified location `{0}` is not supported.. /// - internal static string DirectiveTypeFactory_LocationNotSupported - { - get - { + internal static string DirectiveTypeFactory_LocationNotSupported { + get { return ResourceManager.GetString("DirectiveTypeFactory_LocationNotSupported", resourceCulture); } } - + /// /// Looks up a localized string similar to The cursor cannot be null or empty.. /// - internal static string Edge_CursorIsNull - { - get - { + internal static string Edge_CursorIsNull { + get { return ResourceManager.GetString("Edge_CursorIsNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The enum type `{0}` has no values.. /// - internal static string EnumType_NoValues - { - get - { + internal static string EnumType_NoValues { + get { return ResourceManager.GetString("EnumType_NoValues", resourceCulture); } } - + /// /// Looks up a localized string similar to The enum type extension can only be merged with an enum type.. /// - internal static string EnumTypeExtension_CannotMerge - { - get - { + internal static string EnumTypeExtension_CannotMerge { + get { return ResourceManager.GetString("EnumTypeExtension_CannotMerge", resourceCulture); } } - + /// /// Looks up a localized string similar to The enum value `{0}` of the enum type extension is not assignabe with the target enum type.. /// - internal static string EnumTypeExtension_ValueTypeInvalid - { - get - { + internal static string EnumTypeExtension_ValueTypeInvalid { + get { return ResourceManager.GetString("EnumTypeExtension_ValueTypeInvalid", resourceCulture); } } - + /// /// Looks up a localized string similar to One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.. /// - internal static string EnumValue_Description - { - get - { + internal static string EnumValue_Description { + get { return ResourceManager.GetString("EnumValue_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The inner value of enum value cannot be null or empty.. /// - internal static string EnumValue_ValueIsNull - { - get - { + internal static string EnumValue_ValueIsNull { + get { return ResourceManager.GetString("EnumValue_ValueIsNull", resourceCulture); } } - + /// /// Looks up a localized string similar to Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.. /// - internal static string Field_Description - { - get - { + internal static string Field_Description { + get { return ResourceManager.GetString("Field_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not parse the native value of input field `{0}.{1}`.. /// - internal static string FieldInitHelper_InvalidDefaultValue - { - get - { + internal static string FieldInitHelper_InvalidDefaultValue { + get { return ResourceManager.GetString("FieldInitHelper_InvalidDefaultValue", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} `{1}` has no fields declared.. /// - internal static string FieldInitHelper_NoFields - { - get - { + internal static string FieldInitHelper_NoFields { + get { return ResourceManager.GetString("FieldInitHelper_NoFields", resourceCulture); } } - + /// /// Looks up a localized string similar to The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).. /// - internal static string FloatType_Description - { - get - { + internal static string FloatType_Description { + get { return ResourceManager.GetString("FloatType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.. /// - internal static string IdType_Description - { - get - { + internal static string IdType_Description { + get { return ResourceManager.GetString("IdType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to set the input field value.. /// - internal static string InputField_CannotSetValue - { - get - { + internal static string InputField_CannotSetValue { + get { return ResourceManager.GetString("InputField_CannotSetValue", resourceCulture); } } - + /// /// Looks up a localized string similar to The input object type can only parse object value literals.. /// - internal static string InputObjectType_CannotParseLiteral - { - get - { + internal static string InputObjectType_CannotParseLiteral { + get { return ResourceManager.GetString("InputObjectType_CannotParseLiteral", resourceCulture); } } - + /// /// Looks up a localized string similar to The input object `{0}` does not have any fields.. /// - internal static string InputObjectType_NoFields - { - get - { + internal static string InputObjectType_NoFields { + get { return ResourceManager.GetString("InputObjectType_NoFields", resourceCulture); } } - + /// /// Looks up a localized string similar to The input object type extension can only be merged with an input object type.. /// - internal static string InputObjectTypeExtension_CannotMerge - { - get - { + internal static string InputObjectTypeExtension_CannotMerge { + get { return ResourceManager.GetString("InputObjectTypeExtension_CannotMerge", resourceCulture); } } - + /// /// Looks up a localized string similar to The input value of type `{0}` must not be null.. /// - internal static string InputTypeNonNullCheck_ValueIsNull - { - get - { + internal static string InputTypeNonNullCheck_ValueIsNull { + get { return ResourceManager.GetString("InputTypeNonNullCheck_ValueIsNull", resourceCulture); } } - + /// /// Looks up a localized string similar to A GraphQL-formatted string representing the default value for this input value.. /// - internal static string InputValue_DefaultValue - { - get - { + internal static string InputValue_DefaultValue { + get { return ResourceManager.GetString("InputValue_DefaultValue", resourceCulture); } } - + /// /// Looks up a localized string similar to Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.. /// - internal static string InputValue_Description - { - get - { + internal static string InputValue_Description { + get { return ResourceManager.GetString("InputValue_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The arguments of the interface field {0} from interface {1} and {2} do not match and are implemented by object type {3}.. /// - internal static string InterfaceImplRule_ArgumentsDontMatch - { - get - { + internal static string InterfaceImplRule_ArgumentsDontMatch { + get { return ResourceManager.GetString("InterfaceImplRule_ArgumentsDontMatch", resourceCulture); } } - + /// /// Looks up a localized string similar to Object type {0} does not implement all arguments of field {1} from interface {2}.. /// - internal static string InterfaceImplRule_ArgumentsNotImpl - { - get - { + internal static string InterfaceImplRule_ArgumentsNotImpl { + get { return ResourceManager.GetString("InterfaceImplRule_ArgumentsNotImpl", resourceCulture); } } - + /// /// Looks up a localized string similar to Object type {0} does not implement the field {1} from interface {2}.. /// - internal static string InterfaceImplRule_FieldNotImpl - { - get - { + internal static string InterfaceImplRule_FieldNotImpl { + get { return ResourceManager.GetString("InterfaceImplRule_FieldNotImpl", resourceCulture); } } - + /// /// Looks up a localized string similar to The return type of the interface field {0} from interface {1} and {2} do not match and are implemented by object type {3}.. /// - internal static string InterfaceImplRule_FieldTypeInvalid - { - get - { + internal static string InterfaceImplRule_FieldTypeInvalid { + get { return ResourceManager.GetString("InterfaceImplRule_FieldTypeInvalid", resourceCulture); } } - + /// /// Looks up a localized string similar to The return type of the interface field {0} does not match the field declared by object type {1}.. /// - internal static string InterfaceImplRule_ReturnTypeInvalid - { - get - { + internal static string InterfaceImplRule_ReturnTypeInvalid { + get { return ResourceManager.GetString("InterfaceImplRule_ReturnTypeInvalid", resourceCulture); } } - + /// /// Looks up a localized string similar to The interface type extension can only be merged with an interface type.. /// - internal static string InterfaceTypeExtension_CannotMerge - { - get - { + internal static string InterfaceTypeExtension_CannotMerge { + get { return ResourceManager.GetString("InterfaceTypeExtension_CannotMerge", resourceCulture); } } - + /// /// Looks up a localized string similar to The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.. /// - internal static string IntType_Description - { - get - { + internal static string IntType_Description { + get { return ResourceManager.GetString("IntType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The `Long` scalar type represents non-fractional signed whole 64-bit numeric values. Long can represent values between -(2^63) and 2^63 - 1.. /// - internal static string LongType_Description - { - get - { + internal static string LongType_Description { + get { return ResourceManager.GetString("LongType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The multiplier path scalar represents a valid GraphQL multiplier path string.. /// - internal static string MultiplierPathType_Description - { - get - { + internal static string MultiplierPathType_Description { + get { return ResourceManager.GetString("MultiplierPathType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The multiplier path scalar represents a valid GraphQL multiplier path string.. /// - internal static string Name_Cannot_BeEmpty - { - get - { + internal static string Name_Cannot_BeEmpty { + get { return ResourceManager.GetString("Name_Cannot_BeEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to The name scalar represents a valid GraphQL name as specified in the spec and can be used to refer to fields or types.. /// - internal static string NameType_Description - { - get - { + internal static string NameType_Description { + get { return ResourceManager.GetString("NameType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified type is not an input type.. /// - internal static string NonNullType_NotAnInputType - { - get - { + internal static string NonNullType_NotAnInputType { + get { return ResourceManager.GetString("NonNullType_NotAnInputType", resourceCulture); } } - + /// /// Looks up a localized string similar to The inner type of non-null type must be a nullable type.. /// - internal static string NonNullType_TypeIsNunNullType - { - get - { + internal static string NonNullType_TypeIsNunNullType { + get { return ResourceManager.GetString("NonNullType_TypeIsNunNullType", resourceCulture); } } - + /// /// Looks up a localized string similar to A non null type cannot parse null value literals.. /// - internal static string NonNullType_ValueIsNull - { - get - { + internal static string NonNullType_ValueIsNull { + get { return ResourceManager.GetString("NonNullType_ValueIsNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The field-type must be an output-type.. /// - internal static string ObjectFieldDescriptorBase_FieldType - { - get - { + internal static string ObjectFieldDescriptorBase_FieldType { + get { return ResourceManager.GetString("ObjectFieldDescriptorBase_FieldType", resourceCulture); } } - + /// /// Looks up a localized string similar to The interface base class cannot be used as interface implementation declaration.. /// - internal static string ObjectTypeDescriptor_InterfaceBaseClass - { - get - { + internal static string ObjectTypeDescriptor_InterfaceBaseClass { + get { return ResourceManager.GetString("ObjectTypeDescriptor_InterfaceBaseClass", resourceCulture); } } - + /// /// Looks up a localized string similar to A field-expression must be a property-expression or a method-call-expression.. /// - internal static string ObjectTypeDescriptor_MustBePropertyOrMethod - { - get - { + internal static string ObjectTypeDescriptor_MustBePropertyOrMethod { + get { return ResourceManager.GetString("ObjectTypeDescriptor_MustBePropertyOrMethod", resourceCulture); } } - + /// /// Looks up a localized string similar to Schema types cannot be used as resolver types.. /// - internal static string ObjectTypeDescriptor_Resolver_SchemaType - { - get - { + internal static string ObjectTypeDescriptor_Resolver_SchemaType { + get { return ResourceManager.GetString("ObjectTypeDescriptor_Resolver_SchemaType", resourceCulture); } } - + /// /// Looks up a localized string similar to The object type extension can only be merged with an object type.. /// - internal static string ObjectTypeExtension_CannotMerge - { - get - { + internal static string ObjectTypeExtension_CannotMerge { + get { return ResourceManager.GetString("ObjectTypeExtension_CannotMerge", resourceCulture); } } - + /// /// Looks up a localized string similar to The member expression must specify a property or method that is public and that belongs to the type {0}. /// - internal static string Reflection_MemberMust_BeMethodOrProperty - { - get - { + internal static string Reflection_MemberMust_BeMethodOrProperty { + get { return ResourceManager.GetString("Reflection_MemberMust_BeMethodOrProperty", resourceCulture); } } - + + /// + /// Looks up a localized string similar to The property `{0}` cannot be injected into the resolver. `{0}` does not exist on type `{1}`.. + /// + internal static string ResolverCompiler_ParentPropertyDoesNotExists { + get { + return ResourceManager.GetString("ResolverCompiler_ParentPropertyDoesNotExists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type of property `{0}` is invalid. `{1}` is not assignable to `{2}`. . + /// + internal static string ResolverCompiler_ParentPropertyHasWrongType { + get { + return ResourceManager.GetString("ResolverCompiler_ParentPropertyHasWrongType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The parent of the resolver is of type object. No property can be selected. Parent properties can only be injected in ObjectType<T>.. + /// + internal static string ResolverCompiler_ParentPropertyInvalidSource { + get { + return ResourceManager.GetString("ResolverCompiler_ParentPropertyInvalidSource", resourceCulture); + } + } + /// /// Looks up a localized string similar to A directive type mustn't be one of the base classes `DirectiveType` or `DirectiveType<T>` but must be a type inheriting from `DirectiveType` or `DirectiveType<T>`.. /// - internal static string ResolverCompiler_UnknownParameterType - { - get - { + internal static string ResolverCompiler_UnknownParameterType { + get { return ResourceManager.GetString("ResolverCompiler_UnknownParameterType", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified IResolverFieldBindingBuilder-implementation is not supported.. /// - internal static string ResolverTypeBindingBuilder_FieldBuilderNotSupported - { - get - { + internal static string ResolverTypeBindingBuilder_FieldBuilderNotSupported { + get { return ResourceManager.GetString("ResolverTypeBindingBuilder_FieldBuilderNotSupported", resourceCulture); } } - + /// /// Looks up a localized string similar to The field binding builder is not completed and cannot be added.. /// - internal static string ResolverTypeBindingBuilder_FieldNotComplete - { - get - { + internal static string ResolverTypeBindingBuilder_FieldNotComplete { + get { return ResourceManager.GetString("ResolverTypeBindingBuilder_FieldNotComplete", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} cannot deserialize the given value.. /// - internal static string Scalar_Cannot_Deserialize - { - get - { + internal static string Scalar_Cannot_Deserialize { + get { return ResourceManager.GetString("Scalar_Cannot_Deserialize", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} cannot parse the given literal of type `{1}`.. /// - internal static string Scalar_Cannot_ParseLiteral - { - get - { + internal static string Scalar_Cannot_ParseLiteral { + get { return ResourceManager.GetString("Scalar_Cannot_ParseLiteral", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} cannot parse the given value of type `{1}`.. /// - internal static string Scalar_Cannot_ParseValue - { - get - { + internal static string Scalar_Cannot_ParseValue { + get { return ResourceManager.GetString("Scalar_Cannot_ParseValue", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} cannot serialize the given value.. /// - internal static string Scalar_Cannot_Serialize - { - get - { + internal static string Scalar_Cannot_Serialize { + get { return ResourceManager.GetString("Scalar_Cannot_Serialize", resourceCulture); } } - + /// /// Looks up a localized string similar to A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.. /// - internal static string Schema_Description - { - get - { + internal static string Schema_Description { + get { return ResourceManager.GetString("Schema_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to A list of all directives supported by this server.. /// - internal static string Schema_Directives - { - get - { + internal static string Schema_Directives { + get { return ResourceManager.GetString("Schema_Directives", resourceCulture); } } - + /// /// Looks up a localized string similar to If this server supports mutation, the type that mutation operations will be rooted at.. /// - internal static string Schema_MutationType - { - get - { + internal static string Schema_MutationType { + get { return ResourceManager.GetString("Schema_MutationType", resourceCulture); } } - + /// /// Looks up a localized string similar to The type that query operations will be rooted at.. /// - internal static string Schema_QueryType - { - get - { + internal static string Schema_QueryType { + get { return ResourceManager.GetString("Schema_QueryType", resourceCulture); } } - + /// /// Looks up a localized string similar to If this server support subscription, the type that subscription operations will be rooted at.. /// - internal static string Schema_SubscriptionType - { - get - { + internal static string Schema_SubscriptionType { + get { return ResourceManager.GetString("Schema_SubscriptionType", resourceCulture); } } - + /// /// Looks up a localized string similar to A list of all types supported by this server.. /// - internal static string Schema_Types - { - get - { + internal static string Schema_Types { + get { return ResourceManager.GetString("Schema_Types", resourceCulture); } } - + /// /// Looks up a localized string similar to There is no handler registered that can handle the specified schema binding.. /// - internal static string SchemaBuilder_Binding_CannotBeHandled - { - get - { + internal static string SchemaBuilder_Binding_CannotBeHandled { + get { return ResourceManager.GetString("SchemaBuilder_Binding_CannotBeHandled", resourceCulture); } } - + /// /// Looks up a localized string similar to The schema binding is not valid.. /// - internal static string SchemaBuilder_Binding_Invalid - { - get - { + internal static string SchemaBuilder_Binding_Invalid { + get { return ResourceManager.GetString("SchemaBuilder_Binding_Invalid", resourceCulture); } } - + /// /// Looks up a localized string similar to The given schema has to inherit from TypeSystemObjectBase in order to be initializable.. /// - internal static string SchemaBuilder_ISchemaNotTso - { - get - { + internal static string SchemaBuilder_ISchemaNotTso { + get { return ResourceManager.GetString("SchemaBuilder_ISchemaNotTso", resourceCulture); } } - + /// /// Looks up a localized string similar to schemaType must be a schema type.. /// - internal static string SchemaBuilder_MustBeSchemaType - { - get - { + internal static string SchemaBuilder_MustBeSchemaType { + get { return ResourceManager.GetString("SchemaBuilder_MustBeSchemaType", resourceCulture); } } - + /// /// Looks up a localized string similar to The schema builder was unable to identify the query type of the schema. Either specify which type is the query type or set the schema builder to non-strict validation mode.. /// - internal static string SchemaBuilder_NoQueryType - { - get - { + internal static string SchemaBuilder_NoQueryType { + get { return ResourceManager.GetString("SchemaBuilder_NoQueryType", resourceCulture); } } - + /// /// Looks up a localized string similar to A root type must be a class.. /// - internal static string SchemaBuilder_RootType_MustBeClass - { - get - { + internal static string SchemaBuilder_RootType_MustBeClass { + get { return ResourceManager.GetString("SchemaBuilder_RootType_MustBeClass", resourceCulture); } } - + /// /// Looks up a localized string similar to A root type must be an object type.. /// - internal static string SchemaBuilder_RootType_MustBeObjectType - { - get - { + internal static string SchemaBuilder_RootType_MustBeObjectType { + get { return ResourceManager.GetString("SchemaBuilder_RootType_MustBeObjectType", resourceCulture); } } - + /// /// Looks up a localized string similar to Non-generic schema types are not allowed.. /// - internal static string SchemaBuilder_RootType_NonGenericType - { - get - { + internal static string SchemaBuilder_RootType_NonGenericType { + get { return ResourceManager.GetString("SchemaBuilder_RootType_NonGenericType", resourceCulture); } } - + /// /// Looks up a localized string similar to The given schema has to inherit from `Schema` in order to be initializable.. /// - internal static string SchemaBuilder_SchemaTypeInvalid - { - get - { + internal static string SchemaBuilder_SchemaTypeInvalid { + get { return ResourceManager.GetString("SchemaBuilder_SchemaTypeInvalid", resourceCulture); } } - + /// /// Looks up a localized string similar to A directive type mustn't be one of the base classes `DirectiveType` or `DirectiveType<T>` but must be a type inheriting from `DirectiveType` or `DirectiveType<T>`.. /// - internal static string SchemaBuilderExtensions_DirectiveTypeIsBaseType - { - get - { + internal static string SchemaBuilderExtensions_DirectiveTypeIsBaseType { + get { return ResourceManager.GetString("SchemaBuilderExtensions_DirectiveTypeIsBaseType", resourceCulture); } } - + /// /// Looks up a localized string similar to A directive type must inherit from `DirectiveType` or `DirectiveType<T>`.. /// - internal static string SchemaBuilderExtensions_MustBeDirectiveType - { - get - { + internal static string SchemaBuilderExtensions_MustBeDirectiveType { + get { return ResourceManager.GetString("SchemaBuilderExtensions_MustBeDirectiveType", resourceCulture); } } - + /// /// Looks up a localized string similar to The schema string cannot be null or empty.. /// - internal static string SchemaBuilderExtensions_SchemaIsEmpty - { - get - { + internal static string SchemaBuilderExtensions_SchemaIsEmpty { + get { return ResourceManager.GetString("SchemaBuilderExtensions_SchemaIsEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to The error message mustn't be null or empty.. /// - internal static string SchemaErrorBuilder_MessageIsNull - { - get - { + internal static string SchemaErrorBuilder_MessageIsNull { + get { return ResourceManager.GetString("SchemaErrorBuilder_MessageIsNull", resourceCulture); } } - + /// /// Looks up a localized string similar to Access the current type schema of this server.. /// - internal static string SchemaField_Description - { - get - { + internal static string SchemaField_Description { + get { return ResourceManager.GetString("SchemaField_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to Unknown operation type.. /// - internal static string SchemaSyntaxVisitor_UnknownOperationType - { - get - { + internal static string SchemaSyntaxVisitor_UnknownOperationType { + get { return ResourceManager.GetString("SchemaSyntaxVisitor_UnknownOperationType", resourceCulture); } } - + /// /// Looks up a localized string similar to The `Short` scalar type represents non-fractional signed whole 16-bit numeric values. Short can represent values between -(2^15) and 2^15 - 1.. /// - internal static string ShortType_Description - { - get - { + internal static string ShortType_Description { + get { return ResourceManager.GetString("ShortType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The `{0}` cannot be null or empty.. /// - internal static string String_Argument_NullOrEmpty - { - get - { + internal static string String_Argument_NullOrEmpty { + get { return ResourceManager.GetString("String_Argument_NullOrEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.. /// - internal static string StringType_Description - { - get - { + internal static string StringType_Description { + get { return ResourceManager.GetString("StringType_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum. /// ///Depending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose othe [rest of string was truncated]";. /// - internal static string Type_Description - { - get - { + internal static string Type_Description { + get { return ResourceManager.GetString("Type_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to The configuration delegate mustn't be null.. /// - internal static string TypeConfiguration_ConfigureIsNull - { - get - { + internal static string TypeConfiguration_ConfigureIsNull { + get { return ResourceManager.GetString("TypeConfiguration_ConfigureIsNull", resourceCulture); } } - + /// /// Looks up a localized string similar to Definition mustn't be null.. /// - internal static string TypeConfiguration_DefinitionIsNull - { - get - { + internal static string TypeConfiguration_DefinitionIsNull { + get { return ResourceManager.GetString("TypeConfiguration_DefinitionIsNull", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to convert type from `{0}` to `{1}`. /// - internal static string TypeConvertion_ConvertNotSupported - { - get - { + internal static string TypeConvertion_ConvertNotSupported { + get { return ResourceManager.GetString("TypeConvertion_ConvertNotSupported", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified type is not a schema type.. /// - internal static string TypeDependency_MustBeSchemaType - { - get - { + internal static string TypeDependency_MustBeSchemaType { + get { return ResourceManager.GetString("TypeDependency_MustBeSchemaType", resourceCulture); } } - + /// /// Looks up a localized string similar to The type structure is invalid.. /// - internal static string TypeExtensions_InvalidStructure - { - get - { + internal static string TypeExtensions_InvalidStructure { + get { return ResourceManager.GetString("TypeExtensions_InvalidStructure", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified type kind is not supported.. /// - internal static string TypeExtensions_KindIsNotSupported - { - get - { + internal static string TypeExtensions_KindIsNotSupported { + get { return ResourceManager.GetString("TypeExtensions_KindIsNotSupported", resourceCulture); } } - + /// /// Looks up a localized string similar to The specified type is not a valid list type.. /// - internal static string TypeExtensions_NoListType - { - get - { + internal static string TypeExtensions_NoListType { + get { return ResourceManager.GetString("TypeExtensions_NoListType", resourceCulture); } } - + /// /// Looks up a localized string similar to The given type is not a {0}.. /// - internal static string TypeExtensions_TypeIsNotOfT - { - get - { + internal static string TypeExtensions_TypeIsNotOfT { + get { return ResourceManager.GetString("TypeExtensions_TypeIsNotOfT", resourceCulture); } } - + /// /// Looks up a localized string similar to Request the type information of a single type.. /// - internal static string TypeField_Description - { - get - { + internal static string TypeField_Description { + get { return ResourceManager.GetString("TypeField_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to resolve dependencies {1} for type `{0}`.. /// - internal static string TypeInitializer_CannotResolveDependency - { - get - { + internal static string TypeInitializer_CannotResolveDependency { + get { return ResourceManager.GetString("TypeInitializer_CannotResolveDependency", resourceCulture); } } - + /// /// Looks up a localized string similar to The name `{0}` was already registered by another type.. /// - internal static string TypeInitializer_CompleteName_Duplicate - { - get - { + internal static string TypeInitializer_CompleteName_Duplicate { + get { return ResourceManager.GetString("TypeInitializer_CompleteName_Duplicate", resourceCulture); } } - + /// /// Looks up a localized string similar to The kind of the extension does not match the kind of the type `{0}`.. /// - internal static string TypeInitializer_Merge_KindDoesNotMatch - { - get - { + internal static string TypeInitializer_Merge_KindDoesNotMatch { + get { return ResourceManager.GetString("TypeInitializer_Merge_KindDoesNotMatch", resourceCulture); } } - + + /// + /// Looks up a localized string similar to The member {0} of type {1} is invalid. Parent property selections are not allowed in external resolvers!. + /// + internal static string TypeInitializer_ParentPropertyNotAllowedInExtResolver { + get { + return ResourceManager.GetString("TypeInitializer_ParentPropertyNotAllowedInExtResolver", resourceCulture); + } + } + /// /// Looks up a localized string similar to An enum describing what kind of type a given `__Type` is.. /// - internal static string TypeKind_Description - { - get - { + internal static string TypeKind_Description { + get { return ResourceManager.GetString("TypeKind_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to Indicates this type is an enum. `enumValues` is a valid field.. /// - internal static string TypeKind_Enum - { - get - { + internal static string TypeKind_Enum { + get { return ResourceManager.GetString("TypeKind_Enum", resourceCulture); } } - + /// /// Looks up a localized string similar to Indicates this type is an input object. `inputFields` is a valid field.. /// - internal static string TypeKind_InputObject - { - get - { + internal static string TypeKind_InputObject { + get { return ResourceManager.GetString("TypeKind_InputObject", resourceCulture); } } - + /// /// Looks up a localized string similar to Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.. /// - internal static string TypeKind_Interface - { - get - { + internal static string TypeKind_Interface { + get { return ResourceManager.GetString("TypeKind_Interface", resourceCulture); } } - + /// /// Looks up a localized string similar to Indicates this type is a list. `ofType` is a valid field.. /// - internal static string TypeKind_List - { - get - { + internal static string TypeKind_List { + get { return ResourceManager.GetString("TypeKind_List", resourceCulture); } } - + /// /// Looks up a localized string similar to Indicates this type is a non-null. `ofType` is a valid field.. /// - internal static string TypeKind_NonNull - { - get - { + internal static string TypeKind_NonNull { + get { return ResourceManager.GetString("TypeKind_NonNull", resourceCulture); } } - + /// /// Looks up a localized string similar to Indicates this type is an object. `fields` and `interfaces` are valid fields.. /// - internal static string TypeKind_Object - { - get - { + internal static string TypeKind_Object { + get { return ResourceManager.GetString("TypeKind_Object", resourceCulture); } } - + /// /// Looks up a localized string similar to Indicates this type is a scalar.. /// - internal static string TypeKind_Scalar - { - get - { + internal static string TypeKind_Scalar { + get { return ResourceManager.GetString("TypeKind_Scalar", resourceCulture); } } - + /// /// Looks up a localized string similar to Indicates this type is a union. `possibleTypes` is a valid field.. /// - internal static string TypeKind_Union - { - get - { + internal static string TypeKind_Union { + get { return ResourceManager.GetString("TypeKind_Union", resourceCulture); } } - + /// /// Looks up a localized string similar to The name of the current Object type at runtime.. /// - internal static string TypeNameField_Description - { - get - { + internal static string TypeNameField_Description { + get { return ResourceManager.GetString("TypeNameField_Description", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid type structure.. /// - internal static string TypeNameHelper_InvalidTypeStructure - { - get - { + internal static string TypeNameHelper_InvalidTypeStructure { + get { return ResourceManager.GetString("TypeNameHelper_InvalidTypeStructure", resourceCulture); } } - + /// /// Looks up a localized string similar to Only type system objects are allowed as dependency.. /// - internal static string TypeNameHelper_OnlyTsosAreAllowed - { - get - { + internal static string TypeNameHelper_OnlyTsosAreAllowed { + get { return ResourceManager.GetString("TypeNameHelper_OnlyTsosAreAllowed", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to infer or resolve a schema type from the type reference `{0}`.. /// - internal static string TypeRegistrar_TypesInconsistent - { - get - { + internal static string TypeRegistrar_TypesInconsistent { + get { return ResourceManager.GetString("TypeRegistrar_TypesInconsistent", resourceCulture); } } - + /// /// Looks up a localized string similar to The typeName mustn't be null or empty.. /// - internal static string TypeResourceHelper_TypeNameEmptyOrNull - { - get - { + internal static string TypeResourceHelper_TypeNameEmptyOrNull { + get { return ResourceManager.GetString("TypeResourceHelper_TypeNameEmptyOrNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The description becomes immutable once it was assigned.. /// - internal static string TypeSystemObject_DescriptionImmutable - { - get - { + internal static string TypeSystemObject_DescriptionImmutable { + get { return ResourceManager.GetString("TypeSystemObject_DescriptionImmutable", resourceCulture); } } - + /// /// Looks up a localized string similar to The name becomes immutable once it was assigned.. /// - internal static string TypeSystemObject_NameImmutable - { - get - { + internal static string TypeSystemObject_NameImmutable { + get { return ResourceManager.GetString("TypeSystemObject_NameImmutable", resourceCulture); } } - + /// /// Looks up a localized string similar to The type definition is null which means that the type was initialized incorrectly.. /// - internal static string TypeSystemObjectBase_DefinitionIsNull - { - get - { + internal static string TypeSystemObjectBase_DefinitionIsNull { + get { return ResourceManager.GetString("TypeSystemObjectBase_DefinitionIsNull", resourceCulture); } } - + /// /// Looks up a localized string similar to The type name was not completed correctly and is still empty. Type names are not allowed to remain empty after name completion was executed. ///Type: `{0}`. /// - internal static string TypeSystemObjectBase_NameIsNull - { - get - { + internal static string TypeSystemObjectBase_NameIsNull { + get { return ResourceManager.GetString("TypeSystemObjectBase_NameIsNull", resourceCulture); } } - + /// /// Looks up a localized string similar to A Union type must define one or more unique member types.. /// - internal static string UnionType_MustHaveTypes - { - get - { + internal static string UnionType_MustHaveTypes { + get { return ResourceManager.GetString("UnionType_MustHaveTypes", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to resolve the specified type reference.. /// - internal static string UnionType_UnableToResolveType - { - get - { + internal static string UnionType_UnableToResolveType { + get { return ResourceManager.GetString("UnionType_UnableToResolveType", resourceCulture); } } - + /// /// Looks up a localized string similar to The union type extension can only be merged with an union type.. /// - internal static string UnionTypeExtension_CannotMerge - { - get - { + internal static string UnionTypeExtension_CannotMerge { + get { return ResourceManager.GetString("UnionTypeExtension_CannotMerge", resourceCulture); } } - + /// /// Looks up a localized string similar to Variable `{0}` of type `{1}` must be an input type.. /// - internal static string VariableValueBuilder_InputType - { - get - { + internal static string VariableValueBuilder_InputType { + get { return ResourceManager.GetString("VariableValueBuilder_InputType", resourceCulture); } } - + /// /// Looks up a localized string similar to Variable `{0}` got invalid value.. /// - internal static string VariableValueBuilder_InvalidValue - { - get - { + internal static string VariableValueBuilder_InvalidValue { + get { return ResourceManager.GetString("VariableValueBuilder_InvalidValue", resourceCulture); } } - + /// /// Looks up a localized string similar to The type node kind is not supported.. /// - internal static string VariableValueBuilder_NodeKind - { - get - { + internal static string VariableValueBuilder_NodeKind { + get { return ResourceManager.GetString("VariableValueBuilder_NodeKind", resourceCulture); } } - + /// - /// Looks up a localized string similar to Variable `{0}` of type `{1}` must not be null.. + /// Looks up a localized string similar to Variable `{0}` of type `{1}` must not be null.. /// - internal static string VariableValueBuilder_NonNull - { - get - { + internal static string VariableValueBuilder_NonNull { + get { return ResourceManager.GetString("VariableValueBuilder_NonNull", resourceCulture); } } - + /// - /// Looks up a localized string similar to Detected non-null violation in variable `{0}`. + /// Looks up a localized string similar to Detected non-null violation in variable `{0}`.. /// - internal static string VariableValueBuilder_NonNull_In_Graph - { - get - { + internal static string VariableValueBuilder_NonNull_In_Graph { + get { return ResourceManager.GetString("VariableValueBuilder_NonNull_In_Graph", resourceCulture); } } - + /// /// Looks up a localized string similar to Variable name mustn't be null or empty.. /// - internal static string VariableValueBuilder_VarNameEmpty - { - get - { + internal static string VariableValueBuilder_VarNameEmpty { + get { return ResourceManager.GetString("VariableValueBuilder_VarNameEmpty", resourceCulture); } } diff --git a/src/Core/Types/Properties/TypeResources.resx b/src/Core/Types/Properties/TypeResources.resx index 8ec97d5cf69..bedd306ac6b 100644 --- a/src/Core/Types/Properties/TypeResources.resx +++ b/src/Core/Types/Properties/TypeResources.resx @@ -1,17 +1,17 @@  - - + @@ -584,4 +581,16 @@ Type: `{0}` Unable to convert type from `{0}` to `{1}` - + + The property `{0}` cannot be injected into the resolver. `{0}` does not exist on type `{1}`. + + + The type of property `{0}` is invalid. `{1}` is not assignable to `{2}`. + + + The parent of the resolver is of type object. No property can be selected. Parent properties can only be injected in ObjectType<T>. + + + The member {0} of type {1} is invalid. Parent property selections are not allowed in external resolvers! + + \ No newline at end of file diff --git a/src/Core/Types/Resolvers/Expressions/ResolverCompiler.cs b/src/Core/Types/Resolvers/Expressions/ResolverCompiler.cs index 8512693b874..e99a5b11f35 100644 --- a/src/Core/Types/Resolvers/Expressions/ResolverCompiler.cs +++ b/src/Core/Types/Resolvers/Expressions/ResolverCompiler.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -using System.Threading.Tasks; using HotChocolate.Properties; using HotChocolate.Resolvers.Expressions.Parameters; @@ -29,12 +28,8 @@ protected ResolverCompiler() protected ResolverCompiler( IEnumerable compilers) { - if (compilers == null) - { + _compilers = compilers?.ToArray() ?? throw new ArgumentNullException(nameof(compilers)); - } - - _compilers = compilers.ToArray(); _context = Expression.Parameter(typeof(IResolverContext)); } diff --git a/src/Core/Types/Resolvers/FieldResolver.cs b/src/Core/Types/Resolvers/FieldResolver.cs index 702d2d5e22c..5aaab2aafab 100644 --- a/src/Core/Types/Resolvers/FieldResolver.cs +++ b/src/Core/Types/Resolvers/FieldResolver.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace HotChocolate.Resolvers { diff --git a/src/Core/Types/Types/Descriptors/Contracts/IObjectTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/Contracts/IObjectTypeDescriptor.cs index 9a103b05d0d..39af86936b9 100644 --- a/src/Core/Types/Types/Descriptors/Contracts/IObjectTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/Contracts/IObjectTypeDescriptor.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq.Expressions; using HotChocolate.Language; using HotChocolate.Types.Descriptors.Definitions; diff --git a/src/Core/Types/Types/Descriptors/Extensions/ResolverObjectFieldDescriptorExtensions.cs b/src/Core/Types/Types/Descriptors/Extensions/ResolverObjectFieldDescriptorExtensions.cs index fdf731242cb..bd5b4a9f3da 100644 --- a/src/Core/Types/Types/Descriptors/Extensions/ResolverObjectFieldDescriptorExtensions.cs +++ b/src/Core/Types/Types/Descriptors/Extensions/ResolverObjectFieldDescriptorExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using HotChocolate.Resolvers; diff --git a/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs b/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs index 34095567624..578b9c51eb7 100644 --- a/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs +++ b/src/Core/Types/Types/Descriptors/ObjectTypeDescriptor.cs @@ -136,8 +136,9 @@ private static bool IsResolverRelevant( { ParameterInfo parent = m.GetParameters() .FirstOrDefault(t => t.IsDefined(typeof(ParentAttribute))); + return parent == null - || parent.ParameterType.IsAssignableFrom(sourceType); + || parent.ParameterType.IsAssignableFrom(sourceType); } return false; diff --git a/src/Core/Types/Types/ObjectType.cs b/src/Core/Types/Types/ObjectType.cs index 03d0e12362c..8efb4578fb5 100644 --- a/src/Core/Types/Types/ObjectType.cs +++ b/src/Core/Types/Types/ObjectType.cs @@ -1,7 +1,8 @@ -using System.Globalization; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; +using System.Reflection; using HotChocolate.Configuration; using HotChocolate.Language; using HotChocolate.Resolvers; @@ -229,7 +230,6 @@ private bool IsOfTypeWithName( Type type = result.GetType(); return Name.Equals(type.Name); } - #endregion } } diff --git a/src/Core/Types/Types/ResolveAbstractType.cs b/src/Core/Types/Types/ResolveAbstractType.cs index 488844bec04..6cc9b0a9f83 100644 --- a/src/Core/Types/Types/ResolveAbstractType.cs +++ b/src/Core/Types/Types/ResolveAbstractType.cs @@ -1,4 +1,4 @@ -using HotChocolate.Resolvers; +using HotChocolate.Resolvers; namespace HotChocolate.Types { diff --git a/tools/Build.Core.sln b/tools/Build.Core.sln index 876ae9868aa..64401a0dbfc 100644 --- a/tools/Build.Core.sln +++ b/tools/Build.Core.sln @@ -97,6 +97,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Mongo.Tests", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Tests", "..\src\Core\Types.Sorting.Tests\Types.Sorting.Tests.csproj", "{F2C3763D-4331-4E38-968E-2DD38953F4EB}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection", "..\src\Core\Types.Selection\Types.Selection.csproj", "{962E20E4-1457-48DC-991B-A43394052671}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.Abstractions.Tests", "..\src\Core\Types.Selection.Abstractions.Tests\Types.Selection.Abstractions.Tests.csproj", "{A047E8A4-4780-4D21-A651-53BB74A7CF08}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.InMemory.Tests", "..\src\Core\Types.Selection.InMemory.Tests\Types.Selection.InMemory.Tests.csproj", "{0F045FC2-F74E-42EB-907E-5F2EB7D22026}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.Mongo.Tests", "..\src\Core\Types.Selection.Mongo.Tests\Types.Selection.Mongo.Tests.csproj", "{0F7D8E19-453E-44CF-AF4A-994A9FEA8378}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.SqlServer.Tests", "..\src\Core\Types.Selection.SqlServer.Tests\Types.Selection.SqlServer.Tests.csproj", "{EE30F9E8-490D-4C02-B990-DE4986F8E26A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -671,6 +681,66 @@ Global {F2C3763D-4331-4E38-968E-2DD38953F4EB}.Release|x64.Build.0 = Release|Any CPU {F2C3763D-4331-4E38-968E-2DD38953F4EB}.Release|x86.ActiveCfg = Release|Any CPU {F2C3763D-4331-4E38-968E-2DD38953F4EB}.Release|x86.Build.0 = Release|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Debug|Any CPU.Build.0 = Debug|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Debug|x64.ActiveCfg = Debug|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Debug|x64.Build.0 = Debug|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Debug|x86.ActiveCfg = Debug|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Debug|x86.Build.0 = Debug|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Release|Any CPU.ActiveCfg = Release|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Release|Any CPU.Build.0 = Release|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Release|x64.ActiveCfg = Release|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Release|x64.Build.0 = Release|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Release|x86.ActiveCfg = Release|Any CPU + {962E20E4-1457-48DC-991B-A43394052671}.Release|x86.Build.0 = Release|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Debug|x64.ActiveCfg = Debug|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Debug|x64.Build.0 = Debug|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Debug|x86.ActiveCfg = Debug|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Debug|x86.Build.0 = Debug|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Release|Any CPU.Build.0 = Release|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Release|x64.ActiveCfg = Release|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Release|x64.Build.0 = Release|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Release|x86.ActiveCfg = Release|Any CPU + {A047E8A4-4780-4D21-A651-53BB74A7CF08}.Release|x86.Build.0 = Release|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Debug|x64.ActiveCfg = Debug|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Debug|x64.Build.0 = Debug|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Debug|x86.ActiveCfg = Debug|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Debug|x86.Build.0 = Debug|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Release|Any CPU.Build.0 = Release|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Release|x64.ActiveCfg = Release|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Release|x64.Build.0 = Release|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Release|x86.ActiveCfg = Release|Any CPU + {0F045FC2-F74E-42EB-907E-5F2EB7D22026}.Release|x86.Build.0 = Release|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Debug|x64.ActiveCfg = Debug|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Debug|x64.Build.0 = Debug|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Debug|x86.ActiveCfg = Debug|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Debug|x86.Build.0 = Debug|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Release|Any CPU.Build.0 = Release|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Release|x64.ActiveCfg = Release|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Release|x64.Build.0 = Release|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Release|x86.ActiveCfg = Release|Any CPU + {0F7D8E19-453E-44CF-AF4A-994A9FEA8378}.Release|x86.Build.0 = Release|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Debug|x64.ActiveCfg = Debug|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Debug|x64.Build.0 = Debug|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Debug|x86.ActiveCfg = Debug|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Debug|x86.Build.0 = Debug|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Release|Any CPU.Build.0 = Release|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Release|x64.ActiveCfg = Release|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Release|x64.Build.0 = Release|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Release|x86.ActiveCfg = Release|Any CPU + {EE30F9E8-490D-4C02-B990-DE4986F8E26A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/tools/Build.sln b/tools/Build.sln index ba914d17b7f..5cc221beaa0 100644 --- a/tools/Build.sln +++ b/tools/Build.sln @@ -119,6 +119,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Tests", "..\s EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Mongo.Tests", "..\src\Core\Types.Sorting.Mongo.Tests\Types.Sorting.Mongo.Tests.csproj", "{77432023-09F0-481B-BA86-1D0C233A24AF}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection", "..\src\Core\Types.Selection\Types.Selection.csproj", "{6C26C343-E8C1-4BD9-9293-03A2DC8FF323}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.Abstractions.Tests", "..\src\Core\Types.Selection.Abstractions.Tests\Types.Selection.Abstractions.Tests.csproj", "{2213A868-D26D-4746-A78F-086308BC2A42}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.InMemory.Tests", "..\src\Core\Types.Selection.InMemory.Tests\Types.Selection.InMemory.Tests.csproj", "{B6774002-4497-405A-9695-B33E7EF2E311}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.Mongo.Tests", "..\src\Core\Types.Selection.Mongo.Tests\Types.Selection.Mongo.Tests.csproj", "{119CED8A-6E7C-44A4-A7BF-CFE17CE11788}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Selection.SqlServer.Tests", "..\src\Core\Types.Selection.SqlServer.Tests\Types.Selection.SqlServer.Tests.csproj", "{45E00AFB-2032-4A1D-B229-119785769B9B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -825,6 +835,66 @@ Global {77432023-09F0-481B-BA86-1D0C233A24AF}.Release|x64.Build.0 = Release|Any CPU {77432023-09F0-481B-BA86-1D0C233A24AF}.Release|x86.ActiveCfg = Release|Any CPU {77432023-09F0-481B-BA86-1D0C233A24AF}.Release|x86.Build.0 = Release|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Debug|x64.ActiveCfg = Debug|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Debug|x64.Build.0 = Debug|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Debug|x86.ActiveCfg = Debug|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Debug|x86.Build.0 = Debug|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Release|Any CPU.Build.0 = Release|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Release|x64.ActiveCfg = Release|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Release|x64.Build.0 = Release|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Release|x86.ActiveCfg = Release|Any CPU + {6C26C343-E8C1-4BD9-9293-03A2DC8FF323}.Release|x86.Build.0 = Release|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Debug|x64.ActiveCfg = Debug|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Debug|x64.Build.0 = Debug|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Debug|x86.ActiveCfg = Debug|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Debug|x86.Build.0 = Debug|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Release|Any CPU.Build.0 = Release|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Release|x64.ActiveCfg = Release|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Release|x64.Build.0 = Release|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Release|x86.ActiveCfg = Release|Any CPU + {2213A868-D26D-4746-A78F-086308BC2A42}.Release|x86.Build.0 = Release|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Debug|x64.ActiveCfg = Debug|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Debug|x64.Build.0 = Debug|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Debug|x86.ActiveCfg = Debug|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Debug|x86.Build.0 = Debug|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Release|Any CPU.Build.0 = Release|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Release|x64.ActiveCfg = Release|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Release|x64.Build.0 = Release|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Release|x86.ActiveCfg = Release|Any CPU + {B6774002-4497-405A-9695-B33E7EF2E311}.Release|x86.Build.0 = Release|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Debug|Any CPU.Build.0 = Debug|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Debug|x64.ActiveCfg = Debug|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Debug|x64.Build.0 = Debug|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Debug|x86.ActiveCfg = Debug|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Debug|x86.Build.0 = Debug|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Release|Any CPU.ActiveCfg = Release|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Release|Any CPU.Build.0 = Release|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Release|x64.ActiveCfg = Release|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Release|x64.Build.0 = Release|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Release|x86.ActiveCfg = Release|Any CPU + {119CED8A-6E7C-44A4-A7BF-CFE17CE11788}.Release|x86.Build.0 = Release|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Debug|x64.ActiveCfg = Debug|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Debug|x64.Build.0 = Debug|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Debug|x86.ActiveCfg = Debug|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Debug|x86.Build.0 = Debug|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Release|Any CPU.Build.0 = Release|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Release|x64.ActiveCfg = Release|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Release|x64.Build.0 = Release|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Release|x86.ActiveCfg = Release|Any CPU + {45E00AFB-2032-4A1D-B229-119785769B9B}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE