From f73cdfa2d55ca652cedac9d5b6a87e72ea6c9a14 Mon Sep 17 00:00:00 2001 From: PascalSenn Date: Tue, 17 Nov 2020 16:03:36 +0100 Subject: [PATCH] Projection attributes should change type (#2562) --- ...rDefaultObjectFieldDescriptorExtensions.cs | 1 + ...HotChocolate.Data.Projections.Tests.csproj | 1 + .../ProjectionsAttributeTests.cs | 106 ++++++++++++++++++ ...tributeTests.FirstOrDefault_Attribute.snap | 27 +++++ ...s.FirstOrDefault_Attribute_CustomType.snap | 27 +++++ ...ributeTests.SingleOrDefault_Attribute.snap | 27 +++++ ....SingleOrDefault_Attribute_CustomType.snap | 27 +++++ 7 files changed, 216 insertions(+) create mode 100644 src/HotChocolate/Data/test/Data.Projections.Tests/ProjectionsAttributeTests.cs create mode 100644 src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.FirstOrDefault_Attribute.snap create mode 100644 src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.FirstOrDefault_Attribute_CustomType.snap create mode 100644 src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.SingleOrDefault_Attribute.snap create mode 100644 src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.SingleOrDefault_Attribute_CustomType.snap diff --git a/src/HotChocolate/Data/src/Data/Projections/Extensions/SingleOrDefaultObjectFieldDescriptorExtensions.cs b/src/HotChocolate/Data/src/Data/Projections/Extensions/SingleOrDefaultObjectFieldDescriptorExtensions.cs index ff6770cc194..63e4a884722 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Extensions/SingleOrDefaultObjectFieldDescriptorExtensions.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Extensions/SingleOrDefaultObjectFieldDescriptorExtensions.cs @@ -55,6 +55,7 @@ public static class SingleOrDefaultObjectFieldDescriptorExtensions Type selectionType = typeInfo.NamedType; definition.ResultType = selectionType; + definition.Type = context.TypeInspector.GetTypeRef(selectionType); ILazyTypeConfiguration lazyConfiguration = LazyTypeConfigurationBuilder diff --git a/src/HotChocolate/Data/test/Data.Projections.Tests/HotChocolate.Data.Projections.Tests.csproj b/src/HotChocolate/Data/test/Data.Projections.Tests/HotChocolate.Data.Projections.Tests.csproj index f48a9117d8f..9a8fc859683 100644 --- a/src/HotChocolate/Data/test/Data.Projections.Tests/HotChocolate.Data.Projections.Tests.csproj +++ b/src/HotChocolate/Data/test/Data.Projections.Tests/HotChocolate.Data.Projections.Tests.csproj @@ -14,4 +14,5 @@ + diff --git a/src/HotChocolate/Data/test/Data.Projections.Tests/ProjectionsAttributeTests.cs b/src/HotChocolate/Data/test/Data.Projections.Tests/ProjectionsAttributeTests.cs new file mode 100644 index 00000000000..58ce3da992a --- /dev/null +++ b/src/HotChocolate/Data/test/Data.Projections.Tests/ProjectionsAttributeTests.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using HotChocolate.Types; +using Snapshooter.Xunit; +using Xunit; + +namespace HotChocolate.Data +{ + public class ProjectionAttributeTests + { + [Fact] + public void FirstOrDefault_Attribute() + { + // arrange + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType() + .AddProjections() + .Create(); + + // assert + schema.ToString().MatchSnapshot(); + } + + [Fact] + public void SingleOrDefault_Attribute() + { + // arrange + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType() + .AddProjections() + .Create(); + + // assert + schema.ToString().MatchSnapshot(); + } + + [Fact] + public void FirstOrDefault_Attribute_CustomType() + { + // arrange + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType() + .AddType() + .AddProjections() + .Create(); + + // assert + schema.ToString().MatchSnapshot(); + } + + [Fact] + public void SingleOrDefault_Attribute_CustomType() + { + // arrange + // act + ISchema schema = SchemaBuilder.New() + .AddQueryType() + .AddType() + .AddProjections() + .Create(); + + // assert + schema.ToString().MatchSnapshot(); + } + + public class FooType : ObjectType + { + protected override void Configure(IObjectTypeDescriptor descriptor) + { + descriptor.Name("Renamed"); + descriptor.Field(x => x.Bar).Name("renamed"); + } + } + + public class FirstOrDefaultQuery + { + [UseFirstOrDefault] + [UseProjection] + public IQueryable GetFooQueryable() => throw new NotImplementedException(); + + [UseFirstOrDefault] + [UseProjection] + public IEnumerable GetFooEnumerable() => throw new NotImplementedException(); + } + + public class SingleOrDefaultQuery + { + [UseFirstOrDefault] + [UseProjection] + public IQueryable GetFooQueryable() => throw new NotImplementedException(); + + [UseFirstOrDefault] + [UseProjection] + public IEnumerable GetFooEnumerable() => throw new NotImplementedException(); + } + + public class Foo + { + public string Bar { get; set; } + } + } +} diff --git a/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.FirstOrDefault_Attribute.snap b/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.FirstOrDefault_Attribute.snap new file mode 100644 index 00000000000..e2df607f459 --- /dev/null +++ b/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.FirstOrDefault_Attribute.snap @@ -0,0 +1,27 @@ +schema { + query: FirstOrDefaultQuery +} + +type FirstOrDefaultQuery { + fooQueryable: Foo + fooEnumerable: Foo +} + +type Foo { + bar: String! +} + +"The `@defer` directive may be provided for fragment spreads and inline fragments to inform the executor to delay the execution of the current fragment to indicate deprioritization of the current fragment. A query with `@defer` directive will cause the request to potentially return multiple responses, where non-deferred data is delivered in the initial response and data deferred is delivered in a subsequent response. `@include` and `@skip` take precedence over `@defer`." +directive @defer("If this argument label has a value other than null, it will be passed on to the result of this defer directive. This label is intended to give client applications a way to identify to which fragment a deferred result belongs to." label: String "Deferred when true." if: Boolean) on FRAGMENT_SPREAD | INLINE_FRAGMENT + +"The @deprecated directive is used within the type system definition language to indicate deprecated portions of a GraphQL service’s schema,such as deprecated fields on a type or deprecated enum values." +directive @deprecated("Deprecations include a reason for why it is deprecated, which is formatted using Markdown syntax (as specified by CommonMark)." reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE + +"Directs the executor to include this field or fragment only when the `if` argument is true." +directive @include("Included when true." if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"Directs the executor to skip this field or fragment when the `if` argument is true." +directive @skip("Skipped when true." if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such as asynchronous iterators to provide a partial list in the initial response, and additional list items in subsequent responses. `@include` and `@skip` take precedence over `@stream`." +directive @stream("If this argument label has a value other than null, it will be passed on to the result of this stream directive. This label is intended to give client applications a way to identify to which fragment a streamed result belongs to." label: String "The initial elements that shall be send down to the consumer." initialCount: Int! "Streamed when true." if: Boolean!) on FIELD diff --git a/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.FirstOrDefault_Attribute_CustomType.snap b/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.FirstOrDefault_Attribute_CustomType.snap new file mode 100644 index 00000000000..12409135c51 --- /dev/null +++ b/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.FirstOrDefault_Attribute_CustomType.snap @@ -0,0 +1,27 @@ +schema { + query: FirstOrDefaultQuery +} + +type FirstOrDefaultQuery { + fooQueryable: Renamed + fooEnumerable: Renamed +} + +type Renamed { + renamed: String! +} + +"The `@defer` directive may be provided for fragment spreads and inline fragments to inform the executor to delay the execution of the current fragment to indicate deprioritization of the current fragment. A query with `@defer` directive will cause the request to potentially return multiple responses, where non-deferred data is delivered in the initial response and data deferred is delivered in a subsequent response. `@include` and `@skip` take precedence over `@defer`." +directive @defer("If this argument label has a value other than null, it will be passed on to the result of this defer directive. This label is intended to give client applications a way to identify to which fragment a deferred result belongs to." label: String "Deferred when true." if: Boolean) on FRAGMENT_SPREAD | INLINE_FRAGMENT + +"The @deprecated directive is used within the type system definition language to indicate deprecated portions of a GraphQL service’s schema,such as deprecated fields on a type or deprecated enum values." +directive @deprecated("Deprecations include a reason for why it is deprecated, which is formatted using Markdown syntax (as specified by CommonMark)." reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE + +"Directs the executor to include this field or fragment only when the `if` argument is true." +directive @include("Included when true." if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"Directs the executor to skip this field or fragment when the `if` argument is true." +directive @skip("Skipped when true." if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such as asynchronous iterators to provide a partial list in the initial response, and additional list items in subsequent responses. `@include` and `@skip` take precedence over `@stream`." +directive @stream("If this argument label has a value other than null, it will be passed on to the result of this stream directive. This label is intended to give client applications a way to identify to which fragment a streamed result belongs to." label: String "The initial elements that shall be send down to the consumer." initialCount: Int! "Streamed when true." if: Boolean!) on FIELD diff --git a/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.SingleOrDefault_Attribute.snap b/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.SingleOrDefault_Attribute.snap new file mode 100644 index 00000000000..ca8de8c77d6 --- /dev/null +++ b/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.SingleOrDefault_Attribute.snap @@ -0,0 +1,27 @@ +schema { + query: SingleOrDefaultQuery +} + +type Foo { + bar: String! +} + +type SingleOrDefaultQuery { + fooQueryable: Foo + fooEnumerable: Foo +} + +"The `@defer` directive may be provided for fragment spreads and inline fragments to inform the executor to delay the execution of the current fragment to indicate deprioritization of the current fragment. A query with `@defer` directive will cause the request to potentially return multiple responses, where non-deferred data is delivered in the initial response and data deferred is delivered in a subsequent response. `@include` and `@skip` take precedence over `@defer`." +directive @defer("If this argument label has a value other than null, it will be passed on to the result of this defer directive. This label is intended to give client applications a way to identify to which fragment a deferred result belongs to." label: String "Deferred when true." if: Boolean) on FRAGMENT_SPREAD | INLINE_FRAGMENT + +"The @deprecated directive is used within the type system definition language to indicate deprecated portions of a GraphQL service’s schema,such as deprecated fields on a type or deprecated enum values." +directive @deprecated("Deprecations include a reason for why it is deprecated, which is formatted using Markdown syntax (as specified by CommonMark)." reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE + +"Directs the executor to include this field or fragment only when the `if` argument is true." +directive @include("Included when true." if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"Directs the executor to skip this field or fragment when the `if` argument is true." +directive @skip("Skipped when true." if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such as asynchronous iterators to provide a partial list in the initial response, and additional list items in subsequent responses. `@include` and `@skip` take precedence over `@stream`." +directive @stream("If this argument label has a value other than null, it will be passed on to the result of this stream directive. This label is intended to give client applications a way to identify to which fragment a streamed result belongs to." label: String "The initial elements that shall be send down to the consumer." initialCount: Int! "Streamed when true." if: Boolean!) on FIELD diff --git a/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.SingleOrDefault_Attribute_CustomType.snap b/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.SingleOrDefault_Attribute_CustomType.snap new file mode 100644 index 00000000000..ca317e6d19f --- /dev/null +++ b/src/HotChocolate/Data/test/Data.Projections.Tests/__snapshots__/ProjectionAttributeTests.SingleOrDefault_Attribute_CustomType.snap @@ -0,0 +1,27 @@ +schema { + query: SingleOrDefaultQuery +} + +type Renamed { + renamed: String! +} + +type SingleOrDefaultQuery { + fooQueryable: Renamed + fooEnumerable: Renamed +} + +"The `@defer` directive may be provided for fragment spreads and inline fragments to inform the executor to delay the execution of the current fragment to indicate deprioritization of the current fragment. A query with `@defer` directive will cause the request to potentially return multiple responses, where non-deferred data is delivered in the initial response and data deferred is delivered in a subsequent response. `@include` and `@skip` take precedence over `@defer`." +directive @defer("If this argument label has a value other than null, it will be passed on to the result of this defer directive. This label is intended to give client applications a way to identify to which fragment a deferred result belongs to." label: String "Deferred when true." if: Boolean) on FRAGMENT_SPREAD | INLINE_FRAGMENT + +"The @deprecated directive is used within the type system definition language to indicate deprecated portions of a GraphQL service’s schema,such as deprecated fields on a type or deprecated enum values." +directive @deprecated("Deprecations include a reason for why it is deprecated, which is formatted using Markdown syntax (as specified by CommonMark)." reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE + +"Directs the executor to include this field or fragment only when the `if` argument is true." +directive @include("Included when true." if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"Directs the executor to skip this field or fragment when the `if` argument is true." +directive @skip("Skipped when true." if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such as asynchronous iterators to provide a partial list in the initial response, and additional list items in subsequent responses. `@include` and `@skip` take precedence over `@stream`." +directive @stream("If this argument label has a value other than null, it will be passed on to the result of this stream directive. This label is intended to give client applications a way to identify to which fragment a streamed result belongs to." label: String "The initial elements that shall be send down to the consumer." initialCount: Int! "Streamed when true." if: Boolean!) on FIELD