Skip to content

Commit

Permalink
Fixed Apollo Federation v1 schema output (#7349)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielreynolds1 authored Aug 10, 2024
1 parent 26344d1 commit c16f3d5
Show file tree
Hide file tree
Showing 21 changed files with 805 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ public override void OnAfterCompleteName(

void RegisterImport(MemberInfo element)
{
if (_context.GetFederationVersion() == FederationVersion.Federation10)
{
return;
}

var package = element.GetCustomAttribute<PackageAttribute>();

if (package is null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal static class FederationTypeNames
public const string RequiresScopesDirective_Name = "requiresScopes";
public const string ShareableDirective_Name = "shareable";
public const string FieldSetType_Name = "FieldSet";
public const string LegacyFieldSetType_Name = "_FieldSet";
public const string ScopeType_Name = "Scope";
public const string PolicyType_Name = "Policy";
public const string AnyType_Name = "_Any";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@
<Compile Update="Types\Directives\InterfaceObjectDescriptorExtensions.cs">
<DependentUpon>InterfaceObjectDirective.cs</DependentUpon>
</Compile>
<Compile Update="Types\Directives\KeyLegacySupportAttribute.cs">
<DependentUpon>KeyDirective.cs</DependentUpon>
</Compile>
<Compile Update="Types\Directives\LinkDescriptorExtensions.cs">
<DependentUpon>LinkDirective.cs</DependentUpon>
</Compile>
Expand All @@ -98,9 +95,6 @@
<Compile Update="Types\Directives\ComposeDirectiveDescriptorExtensions.cs">
<DependentUpon>ComposeDirective.cs</DependentUpon>
</Compile>
<Compile Update="Types\FieldSetAttribute.cs">
<DependentUpon>FieldSetType.cs</DependentUpon>
</Compile>
<Compile Update="Types\Directives\AuthenticatedDescriptionExtensions.cs">
<DependentUpon>AuthenticatedDirective.cs</DependentUpon>
</Compile>
Expand All @@ -110,6 +104,9 @@
<Compile Update="Types\Directives\RequiresScopesDescriptorExtensions.cs">
<DependentUpon>RequiresScopesDirective.cs</DependentUpon>
</Compile>
<Compile Update="Types\FieldSetAttribute.cs">
<DependentUpon>FieldSetType.cs</DependentUpon>
</Compile>
<Compile Update="Properties\FederationResources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ protected override void OnConfigure(
if (descriptor.GetFederationVersion() == FederationVersion.Federation10)
{
var desc = (IDirectiveTypeDescriptor<ExternalDirective>)descriptor;
desc.Location(DirectiveLocation.Field);
desc.Extend().Definition.Locations = DirectiveLocation.FieldDefinition;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace HotChocolate.ApolloFederation.Types;
/// and even nested selection sets "id organization { id }".
/// </summary>
[Package(FederationVersionUrls.Federation20)]
[FieldSetTypeLegacySupport]
public sealed class FieldSetType : ScalarType<SelectionSetNode, StringValueNode>
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using HotChocolate.Types.Descriptors;

namespace HotChocolate.ApolloFederation.Types;

internal sealed class FieldSetTypeLegacySupportAttribute : ScalarTypeDescriptorAttribute
{
protected override void OnConfigure(
IDescriptorContext context,
IScalarTypeDescriptor descriptor,
Type type)
{
// federation v1 uses a different name for the scalar.
if (descriptor.GetFederationVersion() == FederationVersion.Federation10)
{
descriptor.Extend().Definition.Name = FederationTypeNames.LegacyFieldSetType_Name;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using CookieCrumble;
using HotChocolate.ApolloFederation.Types;
using HotChocolate.Execution;
using HotChocolate.Types;
using Microsoft.Extensions.DependencyInjection;

namespace HotChocolate.ApolloFederation.Directives.Legacy;

public class ExternalDirectiveTests : FederationTypesTestBase
{
[Fact]
public async Task AnnotateExternalToTypeFieldCodeFirst()
{
// arrange
var schema = await new ServiceCollection()
.AddGraphQL()
.AddApolloFederation(FederationVersion.Federation10)
.AddQueryType(o => o
.Name("Query")
.Field("entity")
.Argument("id", a => a.Type<IntType>())
.Type("User")
.Resolve(_ => new { Id = 1 })
)
.AddObjectType(
o =>
{
o.Name("User")
.Key("id");
o.Field("id")
.Type<IntType>()
.Resolve(_ => 1);
o.Field("idCode")
.Type<StringType>()
.Resolve(_ => default!)
.External();
})
.BuildSchemaAsync();

// act
var query = schema.GetType<ObjectType>("User");

// assert
var directive = Assert.Single(query.Fields["idCode"].Directives);
Assert.Equal(FederationTypeNames.ExternalDirective_Name, directive.Type.Name);

schema.MatchSnapshot();
}

[Fact]
public async Task AnnotateExternalToTypeFieldAnnotationBased()
{
// arrange
var schema = await new ServiceCollection()
.AddGraphQL()
.AddApolloFederation(FederationVersion.Federation10)
.AddQueryType<Query>()
.BuildSchemaAsync();

// act
var query = schema.GetType<ObjectType>("User");

// assert
var directive = Assert.Single(query.Fields["idCode"].Directives);
Assert.Equal(FederationTypeNames.ExternalDirective_Name, directive.Type.Name);

schema.MatchSnapshot();
}
}

public class Query
{
public User GetEntity(int id) => default!;
}

public class User
{
[Key]
public int Id { get; set; }
[External]
public string IdCode { get; set; } = default!;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using CookieCrumble;
using HotChocolate.ApolloFederation.Types;
using HotChocolate.Execution;
using HotChocolate.Types;
using Microsoft.Extensions.DependencyInjection;

namespace HotChocolate.ApolloFederation.Directives.Legacy;

public class KeyDirectiveTests : FederationTypesTestBase
{
[Fact]
public async Task AnnotateKeyToObjectTypeCodeFirst()
{
// arrange
var schema = await new ServiceCollection()
.AddGraphQL()
.AddApolloFederation(FederationVersion.Federation10)
.AddQueryType(o => o
.Name("Query")
.Field("someField")
.Argument("a", a => a.Type<IntType>())
.Type("TestType")
.Resolve(_ => new { Id = 1, Name = "bar" })
)
.AddObjectType(
o =>
{
o.Name("TestType")
.Key("id");
o.Field("id")
.Type<IntType>()
.Resolve(_ => 1);
o.Field("name")
.Type<StringType>()
.Resolve(_ => "bar");
})
.BuildSchemaAsync();

// act
var testType = schema.GetType<ObjectType>("TestType");

// assert
var keyDirective = Assert.Single(testType.Directives);
Assert.Equal(FederationTypeNames.KeyDirective_Name, keyDirective.Type.Name);
Assert.Equal("fields", keyDirective.AsSyntaxNode().Arguments[0].Name.ToString());
Assert.Equal("\"id\"", keyDirective.AsSyntaxNode().Arguments[0].Value.ToString());

schema.MatchSnapshot();
}

[Fact]
public async Task AnnotateKeyToObjectTypeAnnotationBased()
{
// arrange
var schema = await new ServiceCollection()
.AddGraphQL()
.AddApolloFederation(FederationVersion.Federation10)
.AddQueryType<Query<TestTypeClassDirective>>()
.BuildSchemaAsync();

// act
var testType = schema.GetType<ObjectType>("TestTypeClassDirective");

// assert
var keyDirective = Assert.Single(testType.Directives);
Assert.Equal(FederationTypeNames.KeyDirective_Name, keyDirective.Type.Name);
Assert.Equal("fields", keyDirective.AsSyntaxNode().Arguments[0].Name.ToString());
Assert.Equal("\"id\"", keyDirective.AsSyntaxNode().Arguments[0].Value.ToString());

schema.MatchSnapshot();
}

[Fact]
public async Task AnnotateKeyToClassAttributeAnnotationBased()
{
// arrange
var schema = await new ServiceCollection()
.AddGraphQL()
.AddApolloFederation(FederationVersion.Federation10)
.AddQueryType<Query<TestTypePropertyDirective>>()
.BuildSchemaAsync();

// act
var testType = schema.GetType<ObjectType>("TestTypePropertyDirective");

// assert
var keyDirective = Assert.Single(testType.Directives);
Assert.Equal(FederationTypeNames.KeyDirective_Name, keyDirective.Type.Name);
Assert.Equal("fields", keyDirective.AsSyntaxNode().Arguments[0].Name.ToString());
Assert.Equal("\"id\"", keyDirective.AsSyntaxNode().Arguments[0].Value.ToString());

schema.MatchSnapshot();
}

[Fact]
public async Task AnnotateKeyToClassAttributesAnnotationBased()
{
// arrange
var schema = await new ServiceCollection()
.AddGraphQL()
.AddApolloFederation(FederationVersion.Federation10)
.AddQueryType<Query<TestTypePropertyDirectives>>()
.BuildSchemaAsync();

// act
var testType = schema.GetType<ObjectType>("TestTypePropertyDirectives");

// assert
var keyDirective = Assert.Single(testType.Directives);
Assert.Equal(FederationTypeNames.KeyDirective_Name, keyDirective.Type.Name);
Assert.Equal("fields", keyDirective.AsSyntaxNode().Arguments[0].Name.ToString());
Assert.Equal("\"id name\"", keyDirective.AsSyntaxNode().Arguments[0].Value.ToString());

schema.MatchSnapshot();
}

public class Query<T>
{
// ReSharper disable once InconsistentNaming
public T someField(int id) => default!;
}

[Key("id")]
public class TestTypeClassDirective
{
public int Id { get; set; }
}

public class TestTypePropertyDirective
{
[Key]
public int Id { get; set; }
}

public class TestTypePropertyDirectives
{
[Key]
public int Id { get; set; }
[Key]
public string Name { get; set; } = default!;
}
}
Loading

0 comments on commit c16f3d5

Please sign in to comment.