From ee71346383c0dd1670d02a85719f5da99b4f841b Mon Sep 17 00:00:00 2001 From: Ben McCallum Date: Fri, 28 Jan 2022 11:28:25 +0100 Subject: [PATCH 1/3] feat: Support HC v12.6 better (by throwing if `AddGlobalObjectIdentification` wasn't called in startup) --- ...alIdentification_Isnt_Enabled.verified.txt | 3 + .../IdAttributeTests.Schema.verified.txt | 2 +- .../IdAttributeTests.cs | 76 +++++++++++++------ .../PolymorphicIdsSchemaBuilderExtensions.cs | 2 +- .../PolymorphicIdsTypeInterceptor.cs | 16 ++++ src/Directory.Build.props | 2 +- 6 files changed, 75 insertions(+), 26 deletions(-) create mode 100644 src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.PolyId_SchemaBuildError_If_GlobalIdentification_Isnt_Enabled.verified.txt diff --git a/src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.PolyId_SchemaBuildError_If_GlobalIdentification_Isnt_Enabled.verified.txt b/src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.PolyId_SchemaBuildError_If_GlobalIdentification_Isnt_Enabled.verified.txt new file mode 100644 index 0000000..90f92e5 --- /dev/null +++ b/src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.PolyId_SchemaBuildError_If_GlobalIdentification_Isnt_Enabled.verified.txt @@ -0,0 +1,3 @@ +For more details look at the `Errors` property. + +1. Global ID support isn't enabled but is required for AutoGuru.HotChocolate.PolymorphicIds. Please ensure that AddGlobalObjectIdentification is called during startup. diff --git a/src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.Schema.verified.txt b/src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.Schema.verified.txt index 3b0029e..bb469a7 100644 --- a/src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.Schema.verified.txt +++ b/src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.Schema.verified.txt @@ -54,4 +54,4 @@ input LolInput { 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 `@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 \ No newline at end of file +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! = 0 "Streamed when true." if: Boolean) on FIELD \ No newline at end of file diff --git a/src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.cs b/src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.cs index 2435b89..fe059be 100644 --- a/src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.cs +++ b/src/AutoGuru.HotChocolate.PolymorphicIds.Tests/IdAttributeTests.cs @@ -9,6 +9,7 @@ using HotChocolate.Types; using HotChocolate.Types.Relay; using Microsoft.Extensions.DependencyInjection; +using Shouldly; using VerifyTests; using VerifyXunit; using Xunit; @@ -58,6 +59,21 @@ query foo ( nullableGuidIdList(id: [$guidId $null $guidId]) }"; + [Fact] + public async Task PolyId_SchemaBuildError_If_GlobalIdentification_Isnt_Enabled() + { + // arrange + + // act + var schemaBuilder = SchemaBuilder.New() + .AddQueryType() + .AddPolymorphicIds(); + + // assert + var ex = Should.Throw(() => schemaBuilder.Create()); + await Verifier.Verify(ex.Message); + } + [Theory] [InlineData(false)] [InlineData(true)] @@ -74,7 +90,7 @@ public async Task PolyId_On_Arguments(bool isEnabled) .AddQueryType() .AddType() .AddType() - .AddGlobalObjectIdentification() + .AddGlobalObjectIdentification(registerNodeInterface: false) .AddPolymorphicIds(isEnabled ? default : new PolymorphicIdsOptions @@ -116,6 +132,7 @@ public async Task PolyId_On_Arguments_Invalid_Id() await SchemaBuilder.New() .AddQueryType() .AddType() + .AddGlobalObjectIdentification(registerNodeInterface: false) .AddPolymorphicIds() .Create() .MakeExecutable(_executorOptions) @@ -145,6 +162,7 @@ public async Task PolyId_On_Objects(bool isEnabled) await SchemaBuilder.New() .AddQueryType() .AddType() + .AddGlobalObjectIdentification(registerNodeInterface: false) .AddPolymorphicIds(isEnabled ? default : new PolymorphicIdsOptions @@ -200,6 +218,7 @@ public async Task PolyId_On_Objects_Invalid_Id() await SchemaBuilder.New() .AddQueryType() .AddType() + .AddGlobalObjectIdentification(registerNodeInterface: false) .AddPolymorphicIds() .Create() .MakeExecutable(_executorOptions) @@ -239,6 +258,7 @@ public async Task PolyId_On_Objects_Invalid_Id_FluentStyle() .AddQueryType() .AddType() .AddType() + .AddGlobalObjectIdentification(registerNodeInterface: false) .AddPolymorphicIds() .Create(); @@ -270,16 +290,18 @@ public async Task Id_On_Arguments() { // arrange var idSerializer = new IdSerializer(); - var intId = idSerializer.Serialize("Query", 1); - var longId = idSerializer.Serialize("Query", long.MaxValue); - var stringId = idSerializer.Serialize("Query", "abc"); - var guidId = idSerializer.Serialize("Query", new Guid("26a2dc8f-4dab-408c-88c6-523a0a89a2b5")); + var intId = idSerializer.Serialize("Some", 1); + var longId = idSerializer.Serialize("Some", long.MaxValue); + var stringId = idSerializer.Serialize("Some", "abc"); + var guidId = idSerializer.Serialize("Some", new Guid("26a2dc8f-4dab-408c-88c6-523a0a89a2b5")); // act var result = await SchemaBuilder.New() .AddQueryType() .AddType() + .AddType() + .AddGlobalObjectIdentification(registerNodeInterface: false) .Create() .MakeExecutable() .ExecuteAsync( @@ -308,6 +330,7 @@ public async Task Id_On_Objects() await SchemaBuilder.New() .AddQueryType() .AddType() + .AddGlobalObjectIdentification(registerNodeInterface: false) .Create() .MakeExecutable() .ExecuteAsync( @@ -357,6 +380,7 @@ public async Task Id_On_Objects_Given_Nulls() await SchemaBuilder.New() .AddQueryType() .AddType() + .AddGlobalObjectIdentification(registerNodeInterface: false) .Create() .MakeExecutable() .ExecuteAsync( @@ -405,6 +429,7 @@ public async Task Id_On_Objects_InvalidType() await SchemaBuilder.New() .AddQueryType() .AddType() + .AddGlobalObjectIdentification(registerNodeInterface: false) .Create() .MakeExecutable() .ExecuteAsync( @@ -436,25 +461,29 @@ public async Task Id_On_Objects_InvalidId() var someId = "abc"; // act - var result = - await SchemaBuilder.New() - .AddQueryType() - .AddType() - .Create() - .MakeExecutable() - .ExecuteAsync( - QueryRequestBuilder.New() - .SetQuery( - @"query foo ($someId: ID!) { - foo(input: { someId: $someId someIds: [$someId] }) { - someId - ... on FooPayload { - someIds - } + var schema = SchemaBuilder.New() + .AddQueryType() + .AddType() + .AddGlobalObjectIdentification(registerNodeInterface: false) + .Create(); + + var executableSchema = schema + .MakeExecutable(); + + var result = await executableSchema + .ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery( + @"query foo ($someId: ID!) { + foo(input: { someId: $someId someIds: [$someId] }) { + someId + ... on FooPayload { + someIds } - }") - .SetVariableValue("someId", someId) - .Create()); + } + }") + .SetVariableValue("someId", someId) + .Create()); // assert await Verifier.Verify(new @@ -474,6 +503,7 @@ public async Task Schema() SchemaBuilder.New() .AddQueryType() .AddType() + .AddGlobalObjectIdentification(registerNodeInterface: false) .AddPolymorphicIds() .Create() .ToString(); diff --git a/src/AutoGuru.HotChocolate.PolymorphicIds/PolymorphicIdsSchemaBuilderExtensions.cs b/src/AutoGuru.HotChocolate.PolymorphicIds/PolymorphicIdsSchemaBuilderExtensions.cs index cf181f9..08eb0ea 100644 --- a/src/AutoGuru.HotChocolate.PolymorphicIds/PolymorphicIdsSchemaBuilderExtensions.cs +++ b/src/AutoGuru.HotChocolate.PolymorphicIds/PolymorphicIdsSchemaBuilderExtensions.cs @@ -16,7 +16,7 @@ public static ISchemaBuilder AddPolymorphicIds( } options ??= new PolymorphicIdsOptions(); - + return builder .SetContextData(typeof(PolymorphicIdsOptions).FullName!, options) .TryAddTypeInterceptor(); diff --git a/src/AutoGuru.HotChocolate.PolymorphicIds/PolymorphicIdsTypeInterceptor.cs b/src/AutoGuru.HotChocolate.PolymorphicIds/PolymorphicIdsTypeInterceptor.cs index b1117a6..6b02064 100644 --- a/src/AutoGuru.HotChocolate.PolymorphicIds/PolymorphicIdsTypeInterceptor.cs +++ b/src/AutoGuru.HotChocolate.PolymorphicIds/PolymorphicIdsTypeInterceptor.cs @@ -16,6 +16,9 @@ internal sealed class PolymorphicIdsTypeInterceptor : TypeInterceptor { private const string StandardGlobalIdFormatterName = "GlobalIdInputValueFormatter"; + // /src/HotChocolate/Core/src/Types/Types/WellKnownContextData.cs + private const string GlobalIdSupportEnabledContextDataKey = "HotChocolate.Relay.GlobalId"; + private PolymorphicIdsOptions? _options; private PolymorphicIdsOptions Options => _options ?? throw new Exception("Options weren't set up"); @@ -25,6 +28,19 @@ public override void OnBeforeCompleteType( DefinitionBase? definition, IDictionary contextData) { + var globalContextData = completionContext.ContextData; + if (!globalContextData.ContainsKey(GlobalIdSupportEnabledContextDataKey)) + { + var error = SchemaErrorBuilder.New() + .SetMessage( + "Global ID support isn't enabled but is required for " + + "AutoGuru.HotChocolate.PolymorphicIds. Please ensure that " + + $"{nameof(RelaySchemaBuilderExtensions.AddGlobalObjectIdentification)} " + + "is called during startup.") + .Build(); + throw new SchemaException(error); + } + if (completionContext.ContextData.TryGetValue( typeof(PolymorphicIdsOptions).FullName!, out var o) && diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 64e9760..8fe31be 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -17,7 +17,7 @@ enable latest - 12.0.0 + 12.6.0 net5.0; netcoreapp3.1; netstandard2.0 net5.0; netcoreapp3.1 From 72334ffd8ef757fefa0791dab13465a8327b7a1b Mon Sep 17 00:00:00 2001 From: Ben McCallum Date: Fri, 28 Jan 2022 12:18:38 +0100 Subject: [PATCH 2/3] Bump version --- README.md | 3 ++- src/Directory.Build.props | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index db77060..b1f404f 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,8 @@ We strive to match Hot Chocolate's supported .NET target frameworks, though this | HotChocolate | Polymorphic IDs | Our docs | | ------------ | --------------- | -----------| -| v12.0.0 | v2 | right here | +| v12.6.0* | v3 | right here | +| v12.0.0 | v2 | [/v2/main](https://github.com/autoguru-au/hotchocolate-polymorphic-ids/tree/v2/main) branch | | v11.1.0 | v1 | [/v1/main](https://github.com/autoguru-au/hotchocolate-polymorphic-ids/tree/v1/main) branch | \* Denotes unexpected binary incompatibility / breaking change in Hot Chocolate diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 8fe31be..0b3e764 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,7 +4,7 @@ Polymorphic IDs. Polymorphic Relay IDs for HotChocolate GraphQL HotChocolate Relay - 2.1.0 + 3.0.0 https://github.com/autoguru-au/hotchocolate-polymorphic-ids https://github.com/autoguru-au/hotchocolate-polymorphic-ids From 7fa67be22388ac5921850d0d15fddff7f32683b0 Mon Sep 17 00:00:00 2001 From: Ben McCallum Date: Fri, 28 Jan 2022 12:36:57 +0100 Subject: [PATCH 3/3] Another tweak to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b1f404f..68db667 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ dotnet add package AutoGuru.HotChocolate.PolymorphicIds Configure it on your schema (`ISchemaBuilder`) or executor (`IRequestExecutorBuilder`): ```c# +.AddGlobalObjectIdentification() // Required since Hot Chocolate v12.6.0+ .AddPolymorphicIds(new PolymorphicIdsOptions { HandleGuidIds = false, // true by default