diff --git a/src/HotChocolate/Core/src/Types.Analyzers/FileBuilders/DataLoaderFileBuilder.cs b/src/HotChocolate/Core/src/Types.Analyzers/FileBuilders/DataLoaderFileBuilder.cs index 88ee006496b..cbbbb4a5aea 100644 --- a/src/HotChocolate/Core/src/Types.Analyzers/FileBuilders/DataLoaderFileBuilder.cs +++ b/src/HotChocolate/Core/src/Types.Analyzers/FileBuilders/DataLoaderFileBuilder.cs @@ -499,6 +499,7 @@ public void WriteDataLoaderGroupClass( _writer.DecreaseIndent(); _writer.WriteIndentedLine("}"); + _writer.WriteLine(); _writer.WriteIndentedLine("public sealed class {0} : I{0}", groupClassName); _writer.WriteIndentedLine("{"); diff --git a/src/HotChocolate/Core/src/Types.Analyzers/Helpers/DataLoaderAttributeHelper.cs b/src/HotChocolate/Core/src/Types.Analyzers/Helpers/DataLoaderAttributeHelper.cs index 71b79a2a35e..97b5523a85b 100644 --- a/src/HotChocolate/Core/src/Types.Analyzers/Helpers/DataLoaderAttributeHelper.cs +++ b/src/HotChocolate/Core/src/Types.Analyzers/Helpers/DataLoaderAttributeHelper.cs @@ -28,11 +28,15 @@ static void AddGroupNames(ImmutableHashSet.Builder builder, IEnumerable< { if (IsDataLoaderGroupAttribute(attribute.AttributeClass)) { - foreach (var arg in attribute.ConstructorArguments.FirstOrDefault().Values) + var constructorArguments = attribute.ConstructorArguments; + if (constructorArguments.Length > 0) { - if (arg.Value is string groupName) + foreach (var arg in constructorArguments[0].Values) { - builder.Add(groupName); + if (arg.Value is string groupName) + { + builder.Add(groupName); + } } } } diff --git a/src/HotChocolate/Core/src/Types.Analyzers/Models/DataLoaderInfo.cs b/src/HotChocolate/Core/src/Types.Analyzers/Models/DataLoaderInfo.cs index a44e139599a..ebc066f20cf 100644 --- a/src/HotChocolate/Core/src/Types.Analyzers/Models/DataLoaderInfo.cs +++ b/src/HotChocolate/Core/src/Types.Analyzers/Models/DataLoaderInfo.cs @@ -258,7 +258,8 @@ public override bool Equals(SyntaxInfo obj) private bool Equals(DataLoaderInfo other) => AttributeSyntax.IsEquivalentTo(other.AttributeSyntax) - && MethodSyntax.IsEquivalentTo(other.MethodSyntax); + && MethodSyntax.IsEquivalentTo(other.MethodSyntax) + && Groups.SequenceEqual(other.Groups, StringComparer.Ordinal); public override int GetHashCode() => HashCode.Combine(AttributeSyntax, MethodSyntax); diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/DataLoaderTests.cs b/src/HotChocolate/Core/test/Types.Analyzers.Tests/DataLoaderTests.cs index 10db23ff707..413e8156841 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/DataLoaderTests.cs +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/DataLoaderTests.cs @@ -62,6 +62,66 @@ public class Entity """).MatchMarkdownAsync(); } + [Fact] + public async Task GenerateSource_BatchDataLoader_With_Group_Only_On_Class_MatchesSnapshot() + { + await TestHelper.GetGeneratedSourceSnapshot( + """ + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + using HotChocolate; + using GreenDonut; + + namespace TestNamespace; + + [DataLoaderGroup("Group1")] + internal static class TestClass + { + [DataLoader] + public static Task> GetEntityByIdAsync( + IReadOnlyList entityIds, + CancellationToken cancellationToken) + => default!; + } + + public class Entity + { + public int Id { get; set; } + } + """).MatchMarkdownAsync(); + } + + [Fact] + public async Task GenerateSource_BatchDataLoader_With_Group_Only_On_Method_MatchesSnapshot() + { + await TestHelper.GetGeneratedSourceSnapshot( + """ + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + using HotChocolate; + using GreenDonut; + + namespace TestNamespace; + + internal static class TestClass + { + [DataLoaderGroup("Group1")] + [DataLoader] + public static Task> GetEntityByIdAsync( + IReadOnlyList entityIds, + CancellationToken cancellationToken) + => default!; + } + + public class Entity + { + public int Id { get; set; } + } + """).MatchMarkdownAsync(); + } + [Fact] public async Task GenerateSource_GroupedDataLoader_MatchesSnapshot() { diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/DataLoaderTests.GenerateSource_BatchDataLoader_With_Group_MatchesSnapshot.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/DataLoaderTests.GenerateSource_BatchDataLoader_With_Group_MatchesSnapshot.md index acef934fa4c..ce52a9eb22c 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/DataLoaderTests.GenerateSource_BatchDataLoader_With_Group_MatchesSnapshot.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/DataLoaderTests.GenerateSource_BatchDataLoader_With_Group_MatchesSnapshot.md @@ -69,6 +69,7 @@ namespace TestNamespace { IEntityByIdDataLoader EntityById { get; } } + public sealed class Group1 : IGroup1 { private readonly IServiceProvider _services; @@ -96,6 +97,7 @@ namespace TestNamespace { IEntityByIdDataLoader EntityById { get; } } + public sealed class Group2 : IGroup2 { private readonly IServiceProvider _services; diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/DataLoaderTests.GenerateSource_BatchDataLoader_With_Group_Only_On_Class_MatchesSnapshot.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/DataLoaderTests.GenerateSource_BatchDataLoader_With_Group_Only_On_Class_MatchesSnapshot.md new file mode 100644 index 00000000000..7927e10cd18 --- /dev/null +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/DataLoaderTests.GenerateSource_BatchDataLoader_With_Group_Only_On_Class_MatchesSnapshot.md @@ -0,0 +1,129 @@ +# GenerateSource_BatchDataLoader_With_Group_Only_On_Class_MatchesSnapshot + +## GreenDonutDataLoader.735550c.g.cs + +```csharp +// + +#nullable enable +#pragma warning disable + +using System; +using System.Runtime.CompilerServices; +using Microsoft.Extensions.DependencyInjection; +using GreenDonut; + +namespace TestNamespace +{ + public interface IEntityByIdDataLoader + : global::GreenDonut.IDataLoader + { + } + + public sealed class EntityByIdDataLoader + : global::GreenDonut.DataLoaderBase + , IEntityByIdDataLoader + { + private readonly global::System.IServiceProvider _services; + + public EntityByIdDataLoader( + global::System.IServiceProvider services, + global::GreenDonut.IBatchScheduler batchScheduler, + global::GreenDonut.DataLoaderOptions options) + : base(batchScheduler, options) + { + _services = services ?? + throw new global::System.ArgumentNullException(nameof(services)); + } + + protected override async global::System.Threading.Tasks.ValueTask FetchAsync( + global::System.Collections.Generic.IReadOnlyList keys, + global::System.Memory> results, + global::GreenDonut.DataLoaderFetchContext context, + global::System.Threading.CancellationToken ct) + { + var temp = await TestNamespace.TestClass.GetEntityByIdAsync(keys, ct).ConfigureAwait(false); + CopyResults(keys, results.Span, temp); + } + + private void CopyResults( + global::System.Collections.Generic.IReadOnlyList keys, + global::System.Span> results, + global::System.Collections.Generic.IReadOnlyDictionary resultMap) + { + for (var i = 0; i < keys.Count; i++) + { + var key = keys[i]; + if (resultMap.TryGetValue(key, out var value)) + { + results[i] = global::GreenDonut.Result.Resolve(value); + } + else + { + results[i] = global::GreenDonut.Result.Resolve(default(global::TestNamespace.Entity)); + } + } + } + } + public interface IGroup1 + { + IEntityByIdDataLoader EntityById { get; } + } + + public sealed class Group1 : IGroup1 + { + private readonly IServiceProvider _services; + private IEntityByIdDataLoader? _entityById; + + public Group1(IServiceProvider services) + { + _services = services + ?? throw new ArgumentNullException(nameof(services)); + } + public IEntityByIdDataLoader EntityById + { + get + { + if (_entityById is null) + { + _entityById = _services.GetRequiredService(); + } + + return _entityById!; + } + } + } +} + + +``` + +## HotChocolateTypeModule.735550c.g.cs + +```csharp +// + +#nullable enable +#pragma warning disable + +using System; +using System.Runtime.CompilerServices; +using HotChocolate; +using HotChocolate.Types; +using HotChocolate.Execution.Configuration; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static partial class TestsTypesRequestExecutorBuilderExtensions + { + public static IRequestExecutorBuilder AddTestsTypes(this IRequestExecutorBuilder builder) + { + builder.AddDataLoader(); + builder.Services.AddScoped(); + return builder; + } + } +} + +``` + diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/DataLoaderTests.GenerateSource_BatchDataLoader_With_Group_Only_On_Method_MatchesSnapshot.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/DataLoaderTests.GenerateSource_BatchDataLoader_With_Group_Only_On_Method_MatchesSnapshot.md new file mode 100644 index 00000000000..fe1ac6df85e --- /dev/null +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/DataLoaderTests.GenerateSource_BatchDataLoader_With_Group_Only_On_Method_MatchesSnapshot.md @@ -0,0 +1,129 @@ +# GenerateSource_BatchDataLoader_With_Group_Only_On_Method_MatchesSnapshot + +## GreenDonutDataLoader.735550c.g.cs + +```csharp +// + +#nullable enable +#pragma warning disable + +using System; +using System.Runtime.CompilerServices; +using Microsoft.Extensions.DependencyInjection; +using GreenDonut; + +namespace TestNamespace +{ + public interface IEntityByIdDataLoader + : global::GreenDonut.IDataLoader + { + } + + public sealed class EntityByIdDataLoader + : global::GreenDonut.DataLoaderBase + , IEntityByIdDataLoader + { + private readonly global::System.IServiceProvider _services; + + public EntityByIdDataLoader( + global::System.IServiceProvider services, + global::GreenDonut.IBatchScheduler batchScheduler, + global::GreenDonut.DataLoaderOptions options) + : base(batchScheduler, options) + { + _services = services ?? + throw new global::System.ArgumentNullException(nameof(services)); + } + + protected override async global::System.Threading.Tasks.ValueTask FetchAsync( + global::System.Collections.Generic.IReadOnlyList keys, + global::System.Memory> results, + global::GreenDonut.DataLoaderFetchContext context, + global::System.Threading.CancellationToken ct) + { + var temp = await TestNamespace.TestClass.GetEntityByIdAsync(keys, ct).ConfigureAwait(false); + CopyResults(keys, results.Span, temp); + } + + private void CopyResults( + global::System.Collections.Generic.IReadOnlyList keys, + global::System.Span> results, + global::System.Collections.Generic.IReadOnlyDictionary resultMap) + { + for (var i = 0; i < keys.Count; i++) + { + var key = keys[i]; + if (resultMap.TryGetValue(key, out var value)) + { + results[i] = global::GreenDonut.Result.Resolve(value); + } + else + { + results[i] = global::GreenDonut.Result.Resolve(default(global::TestNamespace.Entity)); + } + } + } + } + public interface IGroup1 + { + IEntityByIdDataLoader EntityById { get; } + } + + public sealed class Group1 : IGroup1 + { + private readonly IServiceProvider _services; + private IEntityByIdDataLoader? _entityById; + + public Group1(IServiceProvider services) + { + _services = services + ?? throw new ArgumentNullException(nameof(services)); + } + public IEntityByIdDataLoader EntityById + { + get + { + if (_entityById is null) + { + _entityById = _services.GetRequiredService(); + } + + return _entityById!; + } + } + } +} + + +``` + +## HotChocolateTypeModule.735550c.g.cs + +```csharp +// + +#nullable enable +#pragma warning disable + +using System; +using System.Runtime.CompilerServices; +using HotChocolate; +using HotChocolate.Types; +using HotChocolate.Execution.Configuration; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static partial class TestsTypesRequestExecutorBuilderExtensions + { + public static IRequestExecutorBuilder AddTestsTypes(this IRequestExecutorBuilder builder) + { + builder.AddDataLoader(); + builder.Services.AddScoped(); + return builder; + } + } +} + +``` +