diff --git a/src/HotChocolate/Language/src/Language.SyntaxTree/SyntaxKind.cs b/src/HotChocolate/Language/src/Language.SyntaxTree/SyntaxKind.cs index 0cc8cacdbba..5995f2e71bd 100644 --- a/src/HotChocolate/Language/src/Language.SyntaxTree/SyntaxKind.cs +++ b/src/HotChocolate/Language/src/Language.SyntaxTree/SyntaxKind.cs @@ -44,6 +44,7 @@ public enum SyntaxKind EnumTypeExtension, InputObjectTypeExtension, DirectiveDefinition, - FloatValue + FloatValue, + PublicKeyword } } diff --git a/src/StrawberryShake/Client/StrawberryShake.Client.sln b/src/StrawberryShake/Client/StrawberryShake.Client.sln index a08f78b1124..461f94d5ba9 100644 --- a/src/StrawberryShake/Client/StrawberryShake.Client.sln +++ b/src/StrawberryShake/Client/StrawberryShake.Client.sln @@ -35,6 +35,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StrawberryShake.Persistence EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StrawberryShake.Persistence.SQLite.Tests", "test\Persistence.SQLite.Tests\StrawberryShake.Persistence.SQLite.Tests.csproj", "{9A5345E8-A2EB-410F-BD72-6F268794D2DC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StrawberryShake.Razor", "src\Razor\StrawberryShake.Razor.csproj", "{2A834588-BA60-4906-B111-20AF9FD5B1E6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -204,6 +206,18 @@ Global {9A5345E8-A2EB-410F-BD72-6F268794D2DC}.Release|x64.Build.0 = Release|Any CPU {9A5345E8-A2EB-410F-BD72-6F268794D2DC}.Release|x86.ActiveCfg = Release|Any CPU {9A5345E8-A2EB-410F-BD72-6F268794D2DC}.Release|x86.Build.0 = Release|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Debug|x64.ActiveCfg = Debug|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Debug|x64.Build.0 = Debug|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Debug|x86.ActiveCfg = Debug|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Debug|x86.Build.0 = Debug|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Release|Any CPU.Build.0 = Release|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Release|x64.ActiveCfg = Release|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Release|x64.Build.0 = Release|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Release|x86.ActiveCfg = Release|Any CPU + {2A834588-BA60-4906-B111-20AF9FD5B1E6}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {61894B9B-EC9A-4FC0-AAAF-9922978A5AB8} = {5F283FE4-BB0A-4806-B079-42DBFE0B2EDF} @@ -219,5 +233,6 @@ Global {1B3B2075-6587-45C7-B4DD-65EC76646EB7} = {264FDF20-A58F-476E-9E02-9F082FB65612} {DFFA574E-439F-4FCE-BF6D-CE5BEACA360A} = {5F283FE4-BB0A-4806-B079-42DBFE0B2EDF} {9A5345E8-A2EB-410F-BD72-6F268794D2DC} = {4E0B9145-BE75-4F46-906B-092DFF4AD5CC} + {2A834588-BA60-4906-B111-20AF9FD5B1E6} = {5F283FE4-BB0A-4806-B079-42DBFE0B2EDF} EndGlobalSection EndGlobal diff --git a/src/StrawberryShake/Client/src/Core/IOperationResult.cs b/src/StrawberryShake/Client/src/Core/IOperationResult.cs index 55872a8a9c8..c88b1924c26 100644 --- a/src/StrawberryShake/Client/src/Core/IOperationResult.cs +++ b/src/StrawberryShake/Client/src/Core/IOperationResult.cs @@ -6,20 +6,22 @@ namespace StrawberryShake /// /// The result of a GraphQL operation. /// - public interface IOperationResult : IOperationResult where T : class + public interface IOperationResult + : IOperationResult + where TResultData : class { /// /// Gets the data object or null. /// - new T? Data { get; } + new TResultData? Data { get; } /// /// Gets the data factory which can build from the - /// a new . + /// a new . /// - new IOperationResultDataFactory DataFactory { get; } + new IOperationResultDataFactory DataFactory { get; } - IOperationResult WithData(T data, IOperationResultDataInfo dataInfo); + IOperationResult WithData(TResultData data, IOperationResultDataInfo dataInfo); } /// diff --git a/src/StrawberryShake/Client/src/Razor/DataComponent.cs b/src/StrawberryShake/Client/src/Razor/DataComponent.cs new file mode 100644 index 00000000000..6ffe0e061c7 --- /dev/null +++ b/src/StrawberryShake/Client/src/Razor/DataComponent.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Components; + +namespace StrawberryShake.Razor +{ + public abstract class DataComponent + : ComponentBase + , IDisposable + { + private readonly List _subscriptions = new(); + private bool _disposed; + + [Inject] + protected internal TClientOrOperation ClientOrOperation { get; internal set; } = default!; + + public void Subscribe(Func subscribe) + { + _subscriptions.Add(subscribe(ClientOrOperation)); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + foreach (var subscription in _subscriptions) + { + subscription.Dispose(); + } + } + + _disposed = true; + } + } + } +} diff --git a/src/StrawberryShake/Client/src/Razor/QueryBase.cs b/src/StrawberryShake/Client/src/Razor/QueryBase.cs new file mode 100644 index 00000000000..934eb03b496 --- /dev/null +++ b/src/StrawberryShake/Client/src/Razor/QueryBase.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Rendering; + +namespace StrawberryShake.Razor +{ + public abstract class QueryBase + : ComponentBase + , IDisposable + where TResult : class + { + private IDisposable? _subscription; + private bool _isLoading = true; + private bool _isErrorResult; + private bool _isSuccessResult; + private TResult? _result; + private IReadOnlyList? _errors; + private bool _disposed; + + [Parameter] + public RenderFragment Content { get; set; } = default!; + + [Parameter] + public RenderFragment>? Error { get; set; } + + [Parameter] + public RenderFragment? Loading { get; set; } + + [Parameter] + public ExecutionStrategy Strategy { get; set; } + + protected void Subscribe(IObservable> observable) + { + _subscription = observable.Subscribe(operationResult => + { + _result = operationResult.Data; + _errors = operationResult.Errors; + _isErrorResult = operationResult.IsErrorResult(); + _isSuccessResult = operationResult.IsSuccessResult(); + _isLoading = false; + StateHasChanged(); + }); + } + + protected override void BuildRenderTree(RenderTreeBuilder builder) + { + if (_isLoading && Loading is not null) + { + builder.AddContent(0, Loading); + } + + if (_isErrorResult) + { + builder.AddContent(0, Error, _errors!); + } + + if (_isSuccessResult) + { + builder.AddContent(0, Content, _result!); + } + + base.BuildRenderTree(builder); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + _subscription?.Dispose(); + } + + _disposed = true; + } + } + } +} diff --git a/src/StrawberryShake/Client/src/Razor/StrawberryShake.Razor.csproj b/src/StrawberryShake/Client/src/Razor/StrawberryShake.Razor.csproj new file mode 100644 index 00000000000..53b1679c496 --- /dev/null +++ b/src/StrawberryShake/Client/src/Razor/StrawberryShake.Razor.csproj @@ -0,0 +1,27 @@ + + + + StrawberryShake.Razor + StrawberryShake.Razor + StrawberryShake.Razor + enable + Provides razor components for using StrawberryShake. + net5.0 + net5.0 + + + + + + + + + + + + + + + + + diff --git a/src/StrawberryShake/Client/src/Razor/_Imports.razor b/src/StrawberryShake/Client/src/Razor/_Imports.razor new file mode 100644 index 00000000000..0d41f66c0f3 --- /dev/null +++ b/src/StrawberryShake/Client/src/Razor/_Imports.razor @@ -0,0 +1,2 @@ +@using Microsoft.AspNetCore.Components.Web +@using StrawberryShake diff --git a/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/CSharpGenerator.cs b/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/CSharpGenerator.cs index 0356adbe43f..154d980c227 100644 --- a/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/CSharpGenerator.cs +++ b/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/CSharpGenerator.cs @@ -49,7 +49,8 @@ public static class CSharpGenerator new InputTypeGenerator(), new InputTypeStateInterfaceGenerator(), new ResultInterfaceGenerator(), - new DataTypeGenerator() + new DataTypeGenerator(), + new RazorQueryGenerator() }; public static CSharpGeneratorResult Generate( @@ -240,7 +241,8 @@ private static void GenerateSingleCSharpDocument( var generatorSettings = new CSharpSyntaxGeneratorSettings( settings.NoStore, settings.InputRecords, - settings.EntityRecords); + settings.EntityRecords, + settings.RazorComponents); var results = new List<(Type Generator, CSharpSyntaxGeneratorResult Result)>(); @@ -307,7 +309,8 @@ private static void GenerateMultipleCSharpDocuments( var generatorSettings = new CSharpSyntaxGeneratorSettings( settings.NoStore, settings.InputRecords, - settings.EntityRecords); + settings.EntityRecords, + settings.RazorComponents); var results = new List<(Type Generator, CSharpSyntaxGeneratorResult Result)>(); diff --git a/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/CSharpGeneratorSettings.cs b/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/CSharpGeneratorSettings.cs index 32870d2925c..a7fbb3ceed0 100644 --- a/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/CSharpGeneratorSettings.cs +++ b/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/CSharpGeneratorSettings.cs @@ -39,6 +39,11 @@ public class CSharpGeneratorSettings /// public bool EntityRecords { get; set; } + /// + /// Generate razor components. + /// + public bool RazorComponents { get; set; } + /// /// Generate a single CSharp code file. /// diff --git a/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/Generators/OperationServiceGenerator.cs b/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/Generators/OperationServiceGenerator.cs index 9e88f79ea87..5bc7acbb200 100644 --- a/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/Generators/OperationServiceGenerator.cs +++ b/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/Generators/OperationServiceGenerator.cs @@ -25,7 +25,8 @@ public class OperationServiceGenerator : ClassBaseGenerator private const string _value = "value"; private const string _cancellationToken = "cancellationToken"; - protected override void Generate(OperationDescriptor descriptor, + protected override void Generate( + OperationDescriptor descriptor, CSharpSyntaxGeneratorSettings settings, CodeWriter writer, out string fileName, @@ -53,11 +54,11 @@ protected override void Generate(OperationDescriptor descriptor, .AddConstructor() .SetTypeName(fileName); - var runtimeTypeName = + var resultTypeName = descriptor.ResultTypeReference.GetRuntimeType().Name; AddConstructorAssignedField( - TypeNames.IOperationExecutor.WithGeneric(runtimeTypeName), + TypeNames.IOperationExecutor.WithGeneric(resultTypeName), _operationExecutor, operationExecutor, classBuilder, @@ -67,10 +68,10 @@ protected override void Generate(OperationDescriptor descriptor, if (descriptor is not SubscriptionOperationDescriptor) { - classBuilder.AddMethod(CreateExecuteMethod(descriptor, runtimeTypeName)); + classBuilder.AddMethod(CreateExecuteMethod(descriptor, resultTypeName)); } - classBuilder.AddMethod(CreateWatchMethod(descriptor, runtimeTypeName)); + classBuilder.AddMethod(CreateWatchMethod(descriptor, resultTypeName)); classBuilder.AddMethod(CreateRequestMethod(descriptor)); classBuilder.AddMethod(CreateRequestVariablesMethod(descriptor)); @@ -79,7 +80,7 @@ protected override void Generate(OperationDescriptor descriptor, classBuilder .AddProperty("ResultType") .SetType(TypeNames.Type) - .AsLambda($"typeof({runtimeTypeName})") + .AsLambda($"typeof({resultTypeName})") .SetInterface(TypeNames.IOperationRequestFactory); MethodCallBuilder createRequestCall = MethodCallBuilder diff --git a/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/Generators/RazorQueryGenerator.cs b/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/Generators/RazorQueryGenerator.cs new file mode 100644 index 00000000000..9c6dbc9a846 --- /dev/null +++ b/src/StrawberryShake/CodeGeneration/src/CodeGeneration.CSharp/Generators/RazorQueryGenerator.cs @@ -0,0 +1,122 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using StrawberryShake.CodeGeneration.CSharp.Extensions; +using StrawberryShake.CodeGeneration.Descriptors.Operations; +using StrawberryShake.CodeGeneration.Descriptors.TypeDescriptors; +using StrawberryShake.CodeGeneration.Extensions; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using static StrawberryShake.CodeGeneration.Utilities.NameUtils; + +namespace StrawberryShake.CodeGeneration.CSharp.Generators +{ + public class RazorQueryGenerator : CSharpSyntaxGenerator + { + protected override bool CanHandle( + OperationDescriptor descriptor, + CSharpSyntaxGeneratorSettings settings) => + settings.RazorComponents && descriptor is QueryOperationDescriptor; + + protected override CSharpSyntaxGeneratorResult Generate( + OperationDescriptor descriptor, + CSharpSyntaxGeneratorSettings settings) + { + string componentName = descriptor.Name.Value + "Renderer"; + string resultType = descriptor.ResultTypeReference.GetRuntimeType().ToString(); + + ClassDeclarationSyntax classDeclaration = + ClassDeclaration(componentName) + .AddImplements(TypeNames.QueryBase.WithGeneric(resultType)) + .AddModifiers( + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.PartialKeyword)) + .AddGeneratedAttribute() + .AddMembers(CreateOperationProperty(descriptor.RuntimeType.ToString())); + + foreach (var argument in descriptor.Arguments) + { + classDeclaration = classDeclaration.AddMembers( + CreateArgumentProperty(argument)); + } + + classDeclaration = classDeclaration.AddMembers( + CreateOnInitializedMethod(descriptor.Arguments)); + + return new CSharpSyntaxGeneratorResult( + componentName, + Razor, + $"descriptor.RuntimeType.NamespaceWithoutGlobal.{Razor}", + classDeclaration); + } + + private PropertyDeclarationSyntax CreateOperationProperty(string typeName) => + PropertyDeclaration(ParseTypeName(typeName), "Operation") + .WithAttributeLists( + SingletonList( + AttributeList( + SingletonSeparatedList( + Attribute( + IdentifierName(TypeNames.InjectAttribute)))))) + .AddModifiers(Token(SyntaxKind.InternalKeyword)) + .WithGetterAndSetter() + .WithSuppressNullableWarningExpression(); + + private PropertyDeclarationSyntax CreateArgumentProperty(PropertyDescriptor property) + { + PropertyDeclarationSyntax propertySyntax = + PropertyDeclaration(property.Type.ToTypeSyntax(), GetPropertyName(property.Name)) + .AddModifiers(Token(SyntaxKind.InternalKeyword)) + .WithGetterAndSetter(); + + if (property.Type.IsNonNullable()) + { + propertySyntax = propertySyntax.WithSuppressNullableWarningExpression(); + } + + return propertySyntax; + } + + private MethodDeclarationSyntax CreateOnInitializedMethod( + IReadOnlyList arguments) + { + var argumentList = new List(); + + foreach (var argument in arguments) + { + argumentList.Add(Argument(IdentifierName(GetPropertyName(argument.Name)))); + } + + argumentList.Add( + Argument(IdentifierName("Strategy")) + .WithNameColon(NameColon(IdentifierName("strategy")))); + + SyntaxList bodyStatements = + SingletonList( + ExpressionStatement( + InvocationExpression( + IdentifierName("Subscribe")) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument( + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("Operation"), + IdentifierName("Watch"))) + .WithArgumentList( + ArgumentList( + SeparatedList(argumentList))))))))); + + return MethodDeclaration( + PredefinedType(Token(SyntaxKind.VoidKeyword)), + Identifier("OnInitialized")) + .WithModifiers( + TokenList( + Token(SyntaxKind.ProtectedKeyword), + Token(SyntaxKind.OverrideKeyword))) + .WithBody(Block(bodyStatements)); + } + } +} diff --git a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/CSharpSyntaxGenerator.cs b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/CSharpSyntaxGenerator.cs index 8e4b626721b..e460f31bf5b 100644 --- a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/CSharpSyntaxGenerator.cs @@ -39,6 +39,7 @@ protected abstract CSharpSyntaxGeneratorResult Generate( CSharpSyntaxGeneratorSettings settings); protected static string State => nameof(State); + protected static string Razor => nameof(Razor); protected static string DependencyInjection => nameof(DependencyInjection); protected static string Serialization => nameof(Serialization); } diff --git a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/CSharpSyntaxGeneratorSettings.cs b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/CSharpSyntaxGeneratorSettings.cs index e71261406ed..3cb1536be45 100644 --- a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/CSharpSyntaxGeneratorSettings.cs +++ b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/CSharpSyntaxGeneratorSettings.cs @@ -11,11 +11,12 @@ public class CSharpSyntaxGeneratorSettings public CSharpSyntaxGeneratorSettings( bool noStore, bool inputRecords, - bool entityRecords) + bool entityRecords, bool razorComponents) { NoStore = noStore; InputRecords = inputRecords; EntityRecords = entityRecords; + RazorComponents = razorComponents; } /// @@ -32,5 +33,10 @@ public CSharpSyntaxGeneratorSettings( /// Generates entities as records. /// public bool EntityRecords { get; } + + /// + /// Generate Razor components. + /// + public bool RazorComponents { get; } } } diff --git a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Descriptors/Operations/OperationDescriptor.cs b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Descriptors/Operations/OperationDescriptor.cs index e13a28b4662..53fde912c77 100644 --- a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Descriptors/Operations/OperationDescriptor.cs +++ b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Descriptors/Operations/OperationDescriptor.cs @@ -74,7 +74,7 @@ protected OperationDescriptor( public IReadOnlyList Arguments { get; } /// - /// + /// The request strategy. /// public RequestStrategy Strategy { get; } diff --git a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/TypeNames.cs b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/TypeNames.cs index b40cd9bd840..bde7be7047c 100644 --- a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/TypeNames.cs +++ b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/TypeNames.cs @@ -118,6 +118,8 @@ public static class TypeNames "ServiceCollectionServiceExtensions.AddSingleton"; public const string BuildServiceProvider = GlobalDependencyInjectionNamespace + "ServiceCollectionContainerBuilderExtensions.BuildServiceProvider"; + public const string InjectAttribute = + "global::Microsoft.AspNetCore.Components.InjectAttribute"; public const string IHttpClientFactory = "global::System.Net.Http.IHttpClientFactory"; public const string TryAddSingleton= DependencyInjectionExtensions + "TryAddSingleton"; @@ -128,6 +130,7 @@ public static class TypeNames public const string GlobalDependencyInjectionNamespace = "global::Microsoft.Extensions.DependencyInjection."; public const string DependencyInjectionNamespace = "Microsoft.Extensions.DependencyInjection"; public const string DependencyInjectionExtensions = GlobalDependencyInjectionNamespace +"Extensions.ServiceCollectionDescriptorExtensions."; + public const string QueryBase = StrawberryshakeNamespace + "Razor.QueryBase"; public const string StringSerializer = StrawberryshakeNamespace + "Serialization.StringSerializer"; public const string BooleanSerializer = StrawberryshakeNamespace + "Serialization.BooleanSerializer"; diff --git a/src/StrawberryShake/CodeGeneration/test/CodeGeneration.CSharp.Tests/GeneratorTestHelper.cs b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.CSharp.Tests/GeneratorTestHelper.cs index 4c3e80f2567..85b10c93380 100644 --- a/src/StrawberryShake/CodeGeneration/test/CodeGeneration.CSharp.Tests/GeneratorTestHelper.cs +++ b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.CSharp.Tests/GeneratorTestHelper.cs @@ -91,7 +91,8 @@ public static void AssertResult( TransportProfiles = settings.Profiles, NoStore = settings.NoStore, InputRecords = settings.InputRecords, - EntityRecords = settings.EntityRecords + EntityRecords = settings.EntityRecords, + RazorComponents = settings.RazorComponents }); Assert.False( @@ -272,6 +273,8 @@ public class AssertSettings public bool EntityRecords { get; set; } + public bool RazorComponents { get; set; } + public List Profiles { get; set; } = new(); public RequestStrategyGen RequestStrategy { get; set; } = diff --git a/src/StrawberryShake/CodeGeneration/test/CodeGeneration.CSharp.Tests/StrawberryShake.CodeGeneration.CSharp.Tests.csproj b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.CSharp.Tests/StrawberryShake.CodeGeneration.CSharp.Tests.csproj index 4bcdab022dc..f289ad6f8e0 100644 --- a/src/StrawberryShake/CodeGeneration/test/CodeGeneration.CSharp.Tests/StrawberryShake.CodeGeneration.CSharp.Tests.csproj +++ b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.CSharp.Tests/StrawberryShake.CodeGeneration.CSharp.Tests.csproj @@ -24,7 +24,7 @@ - + Always @@ -32,35 +32,11 @@ Always - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - - diff --git a/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/CSharpCompiler.cs b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/CSharpCompiler.cs new file mode 100644 index 00000000000..a180ef51b8b --- /dev/null +++ b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/CSharpCompiler.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text.Json; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; +using Microsoft.Extensions.DependencyInjection; +using StrawberryShake.Transport.Http; +using StrawberryShake.Transport.InMemory; +using StrawberryShake.Transport.WebSockets; + +namespace StrawberryShake.CodeGeneration.CSharp +{ + internal static class CSharpCompiler + { + // we pin these types so that they are added to this assembly +#pragma warning disable 414 + private static readonly EntityId? _entityId = null!; + private static readonly JsonDocument? _jsonDocument = null!; + private static readonly HttpConnection? _httpConnection = null!; + private static readonly WebSocketConnection? _webSocketConnection = null!; + private static readonly ServiceCollection? _serviceCollection = null!; + private static readonly IHttpClientFactory? _httpClientFactory = null!; + private static readonly HttpClient? _httpClient = null!; + private static readonly InMemoryClient _memoryClient = null!; +#pragma warning restore 414 + + private static readonly CSharpCompilationOptions _options = + new(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug); + + private static readonly HashSet _excludedCodes = new() + { + // warning CS1702: Assuming assembly reference is of different version + "CS1702", + "CS1701" + }; + + public static IReadOnlyList GetDiagnosticErrors(params string[] sourceText) + { + if (sourceText == null) + { + throw new ArgumentNullException(nameof(sourceText)); + } + + if (sourceText.Length == 0) + { + throw new ArgumentException( + "The compiler needs at least one code unit in order " + + "to create an assembly."); + } + + SyntaxTree[] syntaxTree = new SyntaxTree[sourceText.Length]; + for (var i = 0; i < sourceText.Length; i++) + { + syntaxTree[i] = SyntaxFactory.ParseSyntaxTree( + SourceText.From(sourceText[i])); + } + + var assemblyName = $"_{Guid.NewGuid():N}.dll"; + + CSharpCompilation compilation = CSharpCompilation + .Create(assemblyName, syntaxTree, Array.Empty(), _options) + // If we load the references not twice, some assemblies are missing. + .WithReferences(ResolveReferences()); + + return compilation.GetDiagnostics() + .Where(x => !_excludedCodes.Contains(x.Id)) + .ToList(); + } + + private static IEnumerable ResolveReferences() + { + return AppDomain.CurrentDomain.GetAssemblies() + .Where(t => !t.IsDynamic && !string.IsNullOrEmpty(t.Location)) + .Select(assembly => MetadataReference.CreateFromFile(assembly.Location)); + } + } +} diff --git a/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/GeneratorTestHelper.cs b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/GeneratorTestHelper.cs new file mode 100644 index 00000000000..85b10c93380 --- /dev/null +++ b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/GeneratorTestHelper.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using Microsoft.CodeAnalysis; +using ChilliCream.Testing; +using HotChocolate; +using HotChocolate.Language; +using Snapshooter; +using Snapshooter.Xunit; +using StrawberryShake.CodeGeneration.Analyzers; +using StrawberryShake.CodeGeneration.Analyzers.Models; +using StrawberryShake.CodeGeneration.Utilities; +using Xunit; +using Snapshot = Snapshooter.Xunit.Snapshot; +using RequestStrategyGen = StrawberryShake.Tools.Configuration.RequestStrategy; +using static StrawberryShake.CodeGeneration.CSharp.CSharpGenerator; + +namespace StrawberryShake.CodeGeneration.CSharp +{ + public static class GeneratorTestHelper + { + public static IReadOnlyList AssertError(params string[] fileNames) + { + CSharpGeneratorResult result = Generate( + fileNames, + new CSharpGeneratorSettings { Namespace = "Foo.Bar", ClientName = "FooClient" }); + + Assert.True( + result.Errors.Any(), + "It is expected that the result has no generator errors!"); + + return result.Errors; + } + + public static void AssertResult(params string[] sourceTexts) => + AssertResult(true, sourceTexts); + + public static void AssertResult( + bool strictValidation, + params string[] sourceTexts) => + AssertResult( + new AssertSettings { StrictValidation = strictValidation }, + sourceTexts); + + public static void AssertResult( + AssertSettings settings, + params string[] sourceTexts) + { + AssertResult(settings, false, sourceTexts); + } + + public static void AssertResult( + AssertSettings settings, + bool skipWarnings, + params string[] sourceTexts) + { + ClientModel clientModel = + CreateClientModel(sourceTexts, settings.StrictValidation, settings.NoStore); + + var documents = new StringBuilder(); + var documentNames = new HashSet(); + + documents.AppendLine("// ReSharper disable BuiltInTypeReferenceStyle"); + documents.AppendLine("// ReSharper disable RedundantNameQualifier"); + documents.AppendLine("// ReSharper disable ArrangeObjectCreationWhenTypeEvident"); + documents.AppendLine("// ReSharper disable UnusedType.Global"); + documents.AppendLine("// ReSharper disable PartialTypeWithSinglePart"); + documents.AppendLine("// ReSharper disable UnusedMethodReturnValue.Local"); + documents.AppendLine("// ReSharper disable ConvertToAutoProperty"); + documents.AppendLine("// ReSharper disable UnusedMember.Global"); + documents.AppendLine("// ReSharper disable SuggestVarOrType_SimpleTypes"); + documents.AppendLine("// ReSharper disable InconsistentNaming"); + documents.AppendLine(); + + if (settings.Profiles.Count == 0) + { + settings.Profiles.Add(TransportProfile.Default); + } + + CSharpGeneratorResult result = Generate( + clientModel, + new CSharpGeneratorSettings + { + Namespace = settings.Namespace ?? "Foo.Bar", + ClientName = settings.ClientName ?? "FooClient", + StrictSchemaValidation = settings.StrictValidation, + RequestStrategy = settings.RequestStrategy, + TransportProfiles = settings.Profiles, + NoStore = settings.NoStore, + InputRecords = settings.InputRecords, + EntityRecords = settings.EntityRecords, + RazorComponents = settings.RazorComponents + }); + + Assert.False( + result.Errors.Any(), + "It is expected that the result has no generator errors!"); + + foreach (var document in result.Documents) + { + if (!documentNames.Add(document.Name)) + { + Assert.True(false, $"Document name duplicated {document.Name}"); + } + + if (document.Kind == SourceDocumentKind.CSharp) + { + documents.AppendLine("// " + document.Name); + documents.AppendLine(); + documents.AppendLine(document.SourceText); + documents.AppendLine(); + } + else if (document.Kind == SourceDocumentKind.GraphQL) + { + documents.AppendLine("// " + document.Name); + documents.AppendLine("// " + document.Hash); + documents.AppendLine(); + + using var reader = new StringReader(document.SourceText); + string? line; + + do + { + line = reader.ReadLine(); + if (line is not null) + { + documents.AppendLine("// " + line); + } + } while (line is not null); + + documents.AppendLine(); + } + } + + if (settings.SnapshotFile is not null) + { + documents.ToString() + .MatchSnapshot( + new SnapshotFullName( + settings.SnapshotFile, + Snapshot.FullName().FolderPath)); + } + else + { + documents.ToString().MatchSnapshot(); + } + + IReadOnlyList diagnostics = + CSharpCompiler.GetDiagnosticErrors(documents.ToString()); + + if (skipWarnings) + { + diagnostics = diagnostics + .Where(x => x.Severity == DiagnosticSeverity.Error) + .ToList(); + } + + if (diagnostics.Any()) + { + Assert.True(false, + "Diagnostic Errors: \n" + + diagnostics + .Select(x => + $"{x.GetMessage()}" + + $" (Line: {x.Location.GetLineSpan().StartLinePosition.Line})") + .Aggregate((acc, val) => acc + "\n" + val)); + } + } + + public static void AssertStarWarsResult(params string[] sourceTexts) => + AssertStarWarsResult( + new AssertSettings { StrictValidation = true }, + sourceTexts); + + + public static void AssertStarWarsResult( + AssertSettings settings, + params string[] sourceTexts) + { + var source = new string[sourceTexts.Length + 2]; + + source[0] = FileResource.Open("Schema.graphql"); + source[1] = FileResource.Open("Schema.extensions.graphql"); + + Array.Copy( + sourceTexts, + sourceIndex: 0, + source, + destinationIndex: 2, + length: sourceTexts.Length); + + AssertResult(settings, true, source); + } + + public static AssertSettings CreateIntegrationTest( + RequestStrategyGen requestStrategy = RequestStrategyGen.Default, + TransportProfile[]? profiles = null, + bool noStore = false, + [CallerMemberName] string? testName = null) + { + SnapshotFullName snapshotFullName = Snapshot.FullName(); + string testFile = System.IO.Path.Combine( + snapshotFullName.FolderPath, + testName + "Test.cs"); + string ns = "StrawberryShake.CodeGeneration.CSharp.Integration." + testName; + + if (!File.Exists(testFile)) + { + File.WriteAllText( + testFile, + FileResource.Open("TestTemplate.txt") + .Replace("{TestName}", testName) + .Replace("{Namespace}", ns)); + } + + return new AssertSettings + { + ClientName = testName! + "Client", + Namespace = ns, + StrictValidation = true, + SnapshotFile = System.IO.Path.Combine( + snapshotFullName.FolderPath, + testName + "Test.Client.cs"), + RequestStrategy = requestStrategy, + NoStore = noStore, + Profiles = (profiles ?? new[] + { + TransportProfile.Default + }).ToList() + }; + } + + private static ClientModel CreateClientModel( + string[] sourceText, + bool strictValidation, + bool noStore) + { + var files = sourceText + .Select(s => new GraphQLFile(Utf8GraphQLParser.Parse(s))) + .ToList(); + + var typeSystemDocs = files.GetTypeSystemDocuments().ToList(); + var executableDocs = files.GetExecutableDocuments().ToList(); + + var analyzer = new DocumentAnalyzer(); + + analyzer.SetSchema(SchemaHelper.Load(typeSystemDocs, strictValidation, noStore)); + + foreach (DocumentNode executable in executableDocs.Select(file => file.Document)) + { + analyzer.AddDocument(executable); + } + + return analyzer.Analyze(); + } + + public class AssertSettings + { + public string? ClientName { get; set; } + + public string? Namespace { get; set; } + + public bool StrictValidation { get; set; } + + public string? SnapshotFile { get; set; } + + public bool NoStore { get; set; } + + public bool InputRecords { get; set; } + + public bool EntityRecords { get; set; } + + public bool RazorComponents { get; set; } + + public List Profiles { get; set; } = new(); + + public RequestStrategyGen RequestStrategy { get; set; } = + RequestStrategyGen.Default; + } + } +} diff --git a/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/RazorGeneratorTests.cs b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/RazorGeneratorTests.cs new file mode 100644 index 00000000000..0827ea2d8f0 --- /dev/null +++ b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/RazorGeneratorTests.cs @@ -0,0 +1,45 @@ +using StrawberryShake.Razor; +using Xunit; +using static StrawberryShake.CodeGeneration.CSharp.GeneratorTestHelper; + +namespace StrawberryShake.CodeGeneration.CSharp +{ + public class RazorGeneratorTests + { + [Fact] + public void Query_And_Mutation() + { + // force assembly to load! + Assert.NotNull(typeof(QueryBase<>)); + + AssertResult( + settings: new() { RazorComponents = true }, + @"query GetBars($a: String! $b: String) { + bars(a: $a b: $b) { + id + name + } + } + + mutation SaveBars($a: String! $b: String) { + saveBar(a: $a b: $b) { + id + name + } + }", + @"type Query { + bars(a: String!, b: String): [Bar] + } + + type Mutation { + saveBar(a: String!, b: String): Bar + } + + type Bar { + id: String! + name: String + }", + "extend schema @key(fields: \"id\")"); + } + } +} diff --git a/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/StrawberryShake.CodeGeneration.Razor.Tests.csproj b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/StrawberryShake.CodeGeneration.Razor.Tests.csproj new file mode 100644 index 00000000000..566335bcc19 --- /dev/null +++ b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/StrawberryShake.CodeGeneration.Razor.Tests.csproj @@ -0,0 +1,50 @@ + + + + net5.0 + net5.0 + + + + StrawberryShake.CodeGeneration.CSharp.Tests + StrawberryShake + false + + + + StrawberryShake.CodeGeneration.CSharp.Tests + StrawberryShake.CodeGeneration.CSharp + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + + + + + + + + diff --git a/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/__snapshots__/RazorGeneratorTests.Query_And_Mutation.snap b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/__snapshots__/RazorGeneratorTests.Query_And_Mutation.snap new file mode 100644 index 00000000000..deb8bbc8a26 --- /dev/null +++ b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Razor.Tests/__snapshots__/RazorGeneratorTests.Query_And_Mutation.snap @@ -0,0 +1,1367 @@ +// ReSharper disable BuiltInTypeReferenceStyle +// ReSharper disable RedundantNameQualifier +// ReSharper disable ArrangeObjectCreationWhenTypeEvident +// ReSharper disable UnusedType.Global +// ReSharper disable PartialTypeWithSinglePart +// ReSharper disable UnusedMethodReturnValue.Local +// ReSharper disable ConvertToAutoProperty +// ReSharper disable UnusedMember.Global +// ReSharper disable SuggestVarOrType_SimpleTypes +// ReSharper disable InconsistentNaming + +// FooClient + +// +#nullable enable + +namespace descriptor.RuntimeType.NamespaceWithoutGlobal.Razor +{ + // StrawberryShake.CodeGeneration.CSharp.Generators.RazorQueryGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "0.0.0.0")] + public partial class GetBarsRenderer : global::StrawberryShake.Razor.QueryBase + { + [global::Microsoft.AspNetCore.Components.InjectAttribute] + internal global::Foo.Bar.GetBarsQuery Operation + { + get; + set; + } + + = default !; + internal global::System.String A + { + get; + set; + } + + = default !; + internal global::System.String? B + { + get; + set; + } + + protected override void OnInitialized() + { + Subscribe(Operation.Watch(A, B, strategy: Strategy)); + } + } +} + +namespace Foo.Bar +{ + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultTypeGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class GetBarsResult : global::System.IEquatable, IGetBarsResult + { + public GetBarsResult(global::System.Collections.Generic.IReadOnlyList? bars) + { + Bars = bars; + } + + public global::System.Collections.Generic.IReadOnlyList? Bars + { + get; + } + + public virtual global::System.Boolean Equals(GetBarsResult? other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + if (other.GetType() != GetType()) + { + return false; + } + + return (global::StrawberryShake.Helper.ComparisonHelper.SequenceEqual(Bars, other.Bars)); + } + + public override global::System.Boolean Equals(global::System.Object? obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj.GetType() != GetType()) + { + return false; + } + + return Equals((GetBarsResult)obj); + } + + public override global::System.Int32 GetHashCode() + { + unchecked + { + int hash = 5; + if (Bars != null) + { + foreach (var Bars_elm in Bars) + { + if (Bars_elm != null) + { + hash ^= 397 * Bars_elm.GetHashCode(); + } + } + } + + return hash; + } + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultTypeGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class GetBars_Bars_Bar : global::System.IEquatable, IGetBars_Bars_Bar + { + public GetBars_Bars_Bar(global::System.String id, global::System.String? name) + { + Id = id; + Name = name; + } + + public global::System.String Id + { + get; + } + + public global::System.String? Name + { + get; + } + + public virtual global::System.Boolean Equals(GetBars_Bars_Bar? other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + if (other.GetType() != GetType()) + { + return false; + } + + return (Id.Equals(other.Id)) && ((Name is null && other.Name is null) || Name != null && Name.Equals(other.Name)); + } + + public override global::System.Boolean Equals(global::System.Object? obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj.GetType() != GetType()) + { + return false; + } + + return Equals((GetBars_Bars_Bar)obj); + } + + public override global::System.Int32 GetHashCode() + { + unchecked + { + int hash = 5; + hash ^= 397 * Id.GetHashCode(); + if (Name != null) + { + hash ^= 397 * Name.GetHashCode(); + } + + return hash; + } + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultInterfaceGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public interface IGetBarsResult + { + public global::System.Collections.Generic.IReadOnlyList? Bars + { + get; + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultInterfaceGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public interface IGetBars_Bars + { + public global::System.String Id + { + get; + } + + public global::System.String? Name + { + get; + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultInterfaceGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public interface IGetBars_Bars_Bar : IGetBars_Bars + { + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultTypeGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class SaveBarsResult : global::System.IEquatable, ISaveBarsResult + { + public SaveBarsResult(global::Foo.Bar.ISaveBars_SaveBar? saveBar) + { + SaveBar = saveBar; + } + + public global::Foo.Bar.ISaveBars_SaveBar? SaveBar + { + get; + } + + public virtual global::System.Boolean Equals(SaveBarsResult? other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + if (other.GetType() != GetType()) + { + return false; + } + + return (((SaveBar is null && other.SaveBar is null) || SaveBar != null && SaveBar.Equals(other.SaveBar))); + } + + public override global::System.Boolean Equals(global::System.Object? obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj.GetType() != GetType()) + { + return false; + } + + return Equals((SaveBarsResult)obj); + } + + public override global::System.Int32 GetHashCode() + { + unchecked + { + int hash = 5; + if (SaveBar != null) + { + hash ^= 397 * SaveBar.GetHashCode(); + } + + return hash; + } + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultTypeGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class SaveBars_SaveBar_Bar : global::System.IEquatable, ISaveBars_SaveBar_Bar + { + public SaveBars_SaveBar_Bar(global::System.String id, global::System.String? name) + { + Id = id; + Name = name; + } + + public global::System.String Id + { + get; + } + + public global::System.String? Name + { + get; + } + + public virtual global::System.Boolean Equals(SaveBars_SaveBar_Bar? other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + if (other.GetType() != GetType()) + { + return false; + } + + return (Id.Equals(other.Id)) && ((Name is null && other.Name is null) || Name != null && Name.Equals(other.Name)); + } + + public override global::System.Boolean Equals(global::System.Object? obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj.GetType() != GetType()) + { + return false; + } + + return Equals((SaveBars_SaveBar_Bar)obj); + } + + public override global::System.Int32 GetHashCode() + { + unchecked + { + int hash = 5; + hash ^= 397 * Id.GetHashCode(); + if (Name != null) + { + hash ^= 397 * Name.GetHashCode(); + } + + return hash; + } + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultInterfaceGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public interface ISaveBarsResult + { + public global::Foo.Bar.ISaveBars_SaveBar? SaveBar + { + get; + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultInterfaceGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public interface ISaveBars_SaveBar + { + public global::System.String Id + { + get; + } + + public global::System.String? Name + { + get; + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultInterfaceGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public interface ISaveBars_SaveBar_Bar : ISaveBars_SaveBar + { + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.OperationDocumentGenerator + /// + /// Represents the operation service of the GetBars GraphQL operation + /// + /// query GetBars($a: String!, $b: String) { + /// bars(a: $a, b: $b) { + /// __typename + /// id + /// name + /// ... on Bar { + /// id + /// } + /// } + /// } + /// + /// + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class GetBarsQueryDocument : global::StrawberryShake.IDocument + { + private GetBarsQueryDocument() + { + } + + public static GetBarsQueryDocument Instance + { + get; + } + + = new GetBarsQueryDocument(); + public global::StrawberryShake.OperationKind Kind => global::StrawberryShake.OperationKind.Query; + public global::System.ReadOnlySpan Body => new global::System.Byte[]{0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x47, 0x65, 0x74, 0x42, 0x61, 0x72, 0x73, 0x28, 0x24, 0x61, 0x3a, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x21, 0x2c, 0x20, 0x24, 0x62, 0x3a, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x29, 0x20, 0x7b, 0x20, 0x62, 0x61, 0x72, 0x73, 0x28, 0x61, 0x3a, 0x20, 0x24, 0x61, 0x2c, 0x20, 0x62, 0x3a, 0x20, 0x24, 0x62, 0x29, 0x20, 0x7b, 0x20, 0x5f, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x69, 0x64, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x6f, 0x6e, 0x20, 0x42, 0x61, 0x72, 0x20, 0x7b, 0x20, 0x69, 0x64, 0x20, 0x7d, 0x20, 0x7d, 0x20, 0x7d}; + public global::StrawberryShake.DocumentHash Hash + { + get; + } + + = new global::StrawberryShake.DocumentHash("sha1Hash", "d77fc7854088f9716b48874b752a2d2b8be41aef"); + public override global::System.String ToString() + { +#if NETSTANDARD2_0 + return global::System.Text.Encoding.UTF8.GetString(Body.ToArray()); +#else + return global::System.Text.Encoding.UTF8.GetString(Body); +#endif + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.OperationServiceGenerator + /// + /// Represents the operation service of the GetBars GraphQL operation + /// + /// query GetBars($a: String!, $b: String) { + /// bars(a: $a, b: $b) { + /// __typename + /// id + /// name + /// ... on Bar { + /// id + /// } + /// } + /// } + /// + /// + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class GetBarsQuery : global::Foo.Bar.IGetBarsQuery + { + private readonly global::StrawberryShake.IOperationExecutor _operationExecutor; + private readonly global::StrawberryShake.Serialization.IInputValueFormatter _stringFormatter; + public GetBarsQuery(global::StrawberryShake.IOperationExecutor operationExecutor, global::StrawberryShake.Serialization.ISerializerResolver serializerResolver) + { + _operationExecutor = operationExecutor ?? throw new global::System.ArgumentNullException(nameof(operationExecutor)); + _stringFormatter = serializerResolver.GetInputValueFormatter("String"); + } + + global::System.Type global::StrawberryShake.IOperationRequestFactory.ResultType => typeof(IGetBarsResult); + public async global::System.Threading.Tasks.Task> ExecuteAsync(global::System.String a, global::System.String? b, global::System.Threading.CancellationToken cancellationToken = default) + { + var request = CreateRequest(a, b); + return await _operationExecutor.ExecuteAsync(request, cancellationToken).ConfigureAwait(false); + } + + public global::System.IObservable> Watch(global::System.String a, global::System.String? b, global::StrawberryShake.ExecutionStrategy? strategy = null) + { + var request = CreateRequest(a, b); + return _operationExecutor.Watch(request, strategy); + } + + private global::StrawberryShake.OperationRequest CreateRequest(global::System.String a, global::System.String? b) + { + var variables = new global::System.Collections.Generic.Dictionary(); + variables.Add("a", FormatA(a)); + variables.Add("b", FormatB(b)); + return CreateRequest(variables); + } + + private global::StrawberryShake.OperationRequest CreateRequest(global::System.Collections.Generic.IReadOnlyDictionary? variables) + { + return new global::StrawberryShake.OperationRequest(id: GetBarsQueryDocument.Instance.Hash.Value, name: "GetBars", document: GetBarsQueryDocument.Instance, strategy: global::StrawberryShake.RequestStrategy.Default, variables: variables); + } + + private global::System.Object? FormatA(global::System.String value) + { + if (value is null) + { + throw new global::System.ArgumentNullException(nameof(value)); + } + + return _stringFormatter.Format(value); + } + + private global::System.Object? FormatB(global::System.String? value) + { + if (value is null) + { + return value; + } + else + { + return _stringFormatter.Format(value); + } + } + + global::StrawberryShake.OperationRequest global::StrawberryShake.IOperationRequestFactory.Create(global::System.Collections.Generic.IReadOnlyDictionary? variables) + { + return CreateRequest(variables!); + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.OperationServiceInterfaceGenerator + /// + /// Represents the operation service of the GetBars GraphQL operation + /// + /// query GetBars($a: String!, $b: String) { + /// bars(a: $a, b: $b) { + /// __typename + /// id + /// name + /// ... on Bar { + /// id + /// } + /// } + /// } + /// + /// + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public interface IGetBarsQuery : global::StrawberryShake.IOperationRequestFactory + { + global::System.Threading.Tasks.Task> ExecuteAsync(global::System.String a, global::System.String? b, global::System.Threading.CancellationToken cancellationToken = default); + global::System.IObservable> Watch(global::System.String a, global::System.String? b, global::StrawberryShake.ExecutionStrategy? strategy = null); + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.OperationDocumentGenerator + /// + /// Represents the operation service of the SaveBars GraphQL operation + /// + /// mutation SaveBars($a: String!, $b: String) { + /// saveBar(a: $a, b: $b) { + /// __typename + /// id + /// name + /// ... on Bar { + /// id + /// } + /// } + /// } + /// + /// + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class SaveBarsMutationDocument : global::StrawberryShake.IDocument + { + private SaveBarsMutationDocument() + { + } + + public static SaveBarsMutationDocument Instance + { + get; + } + + = new SaveBarsMutationDocument(); + public global::StrawberryShake.OperationKind Kind => global::StrawberryShake.OperationKind.Mutation; + public global::System.ReadOnlySpan Body => new global::System.Byte[]{0x6d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x61, 0x76, 0x65, 0x42, 0x61, 0x72, 0x73, 0x28, 0x24, 0x61, 0x3a, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x21, 0x2c, 0x20, 0x24, 0x62, 0x3a, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x29, 0x20, 0x7b, 0x20, 0x73, 0x61, 0x76, 0x65, 0x42, 0x61, 0x72, 0x28, 0x61, 0x3a, 0x20, 0x24, 0x61, 0x2c, 0x20, 0x62, 0x3a, 0x20, 0x24, 0x62, 0x29, 0x20, 0x7b, 0x20, 0x5f, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x69, 0x64, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x6f, 0x6e, 0x20, 0x42, 0x61, 0x72, 0x20, 0x7b, 0x20, 0x69, 0x64, 0x20, 0x7d, 0x20, 0x7d, 0x20, 0x7d}; + public global::StrawberryShake.DocumentHash Hash + { + get; + } + + = new global::StrawberryShake.DocumentHash("sha1Hash", "46ced9034dad969a5b30d75b8a91366be7ad75b5"); + public override global::System.String ToString() + { +#if NETSTANDARD2_0 + return global::System.Text.Encoding.UTF8.GetString(Body.ToArray()); +#else + return global::System.Text.Encoding.UTF8.GetString(Body); +#endif + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.OperationServiceGenerator + /// + /// Represents the operation service of the SaveBars GraphQL operation + /// + /// mutation SaveBars($a: String!, $b: String) { + /// saveBar(a: $a, b: $b) { + /// __typename + /// id + /// name + /// ... on Bar { + /// id + /// } + /// } + /// } + /// + /// + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class SaveBarsMutation : global::Foo.Bar.ISaveBarsMutation + { + private readonly global::StrawberryShake.IOperationExecutor _operationExecutor; + private readonly global::StrawberryShake.Serialization.IInputValueFormatter _stringFormatter; + public SaveBarsMutation(global::StrawberryShake.IOperationExecutor operationExecutor, global::StrawberryShake.Serialization.ISerializerResolver serializerResolver) + { + _operationExecutor = operationExecutor ?? throw new global::System.ArgumentNullException(nameof(operationExecutor)); + _stringFormatter = serializerResolver.GetInputValueFormatter("String"); + } + + global::System.Type global::StrawberryShake.IOperationRequestFactory.ResultType => typeof(ISaveBarsResult); + public async global::System.Threading.Tasks.Task> ExecuteAsync(global::System.String a, global::System.String? b, global::System.Threading.CancellationToken cancellationToken = default) + { + var request = CreateRequest(a, b); + return await _operationExecutor.ExecuteAsync(request, cancellationToken).ConfigureAwait(false); + } + + public global::System.IObservable> Watch(global::System.String a, global::System.String? b, global::StrawberryShake.ExecutionStrategy? strategy = null) + { + var request = CreateRequest(a, b); + return _operationExecutor.Watch(request, strategy); + } + + private global::StrawberryShake.OperationRequest CreateRequest(global::System.String a, global::System.String? b) + { + var variables = new global::System.Collections.Generic.Dictionary(); + variables.Add("a", FormatA(a)); + variables.Add("b", FormatB(b)); + return CreateRequest(variables); + } + + private global::StrawberryShake.OperationRequest CreateRequest(global::System.Collections.Generic.IReadOnlyDictionary? variables) + { + return new global::StrawberryShake.OperationRequest(id: SaveBarsMutationDocument.Instance.Hash.Value, name: "SaveBars", document: SaveBarsMutationDocument.Instance, strategy: global::StrawberryShake.RequestStrategy.Default, variables: variables); + } + + private global::System.Object? FormatA(global::System.String value) + { + if (value is null) + { + throw new global::System.ArgumentNullException(nameof(value)); + } + + return _stringFormatter.Format(value); + } + + private global::System.Object? FormatB(global::System.String? value) + { + if (value is null) + { + return value; + } + else + { + return _stringFormatter.Format(value); + } + } + + global::StrawberryShake.OperationRequest global::StrawberryShake.IOperationRequestFactory.Create(global::System.Collections.Generic.IReadOnlyDictionary? variables) + { + return CreateRequest(variables!); + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.OperationServiceInterfaceGenerator + /// + /// Represents the operation service of the SaveBars GraphQL operation + /// + /// mutation SaveBars($a: String!, $b: String) { + /// saveBar(a: $a, b: $b) { + /// __typename + /// id + /// name + /// ... on Bar { + /// id + /// } + /// } + /// } + /// + /// + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public interface ISaveBarsMutation : global::StrawberryShake.IOperationRequestFactory + { + global::System.Threading.Tasks.Task> ExecuteAsync(global::System.String a, global::System.String? b, global::System.Threading.CancellationToken cancellationToken = default); + global::System.IObservable> Watch(global::System.String a, global::System.String? b, global::StrawberryShake.ExecutionStrategy? strategy = null); + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ClientGenerator + /// + /// Represents the FooClient GraphQL client + /// + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class FooClient : global::Foo.Bar.IFooClient + { + private readonly global::Foo.Bar.IGetBarsQuery _getBars; + private readonly global::Foo.Bar.ISaveBarsMutation _saveBars; + public FooClient(global::Foo.Bar.IGetBarsQuery getBars, global::Foo.Bar.ISaveBarsMutation saveBars) + { + _getBars = getBars ?? throw new global::System.ArgumentNullException(nameof(getBars)); + _saveBars = saveBars ?? throw new global::System.ArgumentNullException(nameof(saveBars)); + } + + public static global::System.String ClientName => "FooClient"; + public global::Foo.Bar.IGetBarsQuery GetBars => _getBars; + public global::Foo.Bar.ISaveBarsMutation SaveBars => _saveBars; + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ClientInterfaceGenerator + /// + /// Represents the FooClient GraphQL client + /// + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public interface IFooClient + { + global::Foo.Bar.IGetBarsQuery GetBars + { + get; + } + + global::Foo.Bar.ISaveBarsMutation SaveBars + { + get; + } + } +} + +namespace Foo.Bar.State +{ + // StrawberryShake.CodeGeneration.CSharp.Generators.EntityTypeGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "0.0.0.0")] + public partial class BarEntity + { + public BarEntity(global::System.String id = default !, global::System.String? name = default !) + { + Id = id; + Name = name; + } + + public global::System.String Id + { + get; + } + + public global::System.String? Name + { + get; + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultDataFactoryGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class GetBarsResultFactory : global::StrawberryShake.IOperationResultDataFactory + { + private readonly global::StrawberryShake.IEntityStore _entityStore; + private readonly global::StrawberryShake.IEntityMapper _getBars_Bars_BarFromBarEntityMapper; + public GetBarsResultFactory(global::StrawberryShake.IEntityStore entityStore, global::StrawberryShake.IEntityMapper getBars_Bars_BarFromBarEntityMapper) + { + _entityStore = entityStore ?? throw new global::System.ArgumentNullException(nameof(entityStore)); + _getBars_Bars_BarFromBarEntityMapper = getBars_Bars_BarFromBarEntityMapper ?? throw new global::System.ArgumentNullException(nameof(getBars_Bars_BarFromBarEntityMapper)); + } + + global::System.Type global::StrawberryShake.IOperationResultDataFactory.ResultType => typeof(global::Foo.Bar.IGetBarsResult); + public GetBarsResult Create(global::StrawberryShake.IOperationResultDataInfo dataInfo, global::StrawberryShake.IEntityStoreSnapshot? snapshot = null) + { + if (snapshot is null) + { + snapshot = _entityStore.CurrentSnapshot; + } + + if (dataInfo is GetBarsResultInfo info) + { + return new GetBarsResult(MapIGetBars_BarsArray(info.Bars, snapshot)); + } + + throw new global::System.ArgumentException("GetBarsResultInfo expected."); + } + + private global::System.Collections.Generic.IReadOnlyList? MapIGetBars_BarsArray(global::System.Collections.Generic.IReadOnlyList? list, global::StrawberryShake.IEntityStoreSnapshot snapshot) + { + if (list is null) + { + return null; + } + + var bars = new global::System.Collections.Generic.List(); + foreach (global::StrawberryShake.EntityId? child in list) + { + bars.Add(MapIGetBars_Bars(child, snapshot)); + } + + return bars; + } + + private global::Foo.Bar.IGetBars_Bars? MapIGetBars_Bars(global::StrawberryShake.EntityId? entityId, global::StrawberryShake.IEntityStoreSnapshot snapshot) + { + if (entityId is null) + { + return null; + } + + if (entityId.Value.Name.Equals("Bar", global::System.StringComparison.Ordinal)) + { + return _getBars_Bars_BarFromBarEntityMapper.Map(snapshot.GetEntity(entityId.Value) ?? throw new global::StrawberryShake.GraphQLClientException()); + } + + throw new global::System.NotSupportedException(); + } + + global::System.Object global::StrawberryShake.IOperationResultDataFactory.Create(global::StrawberryShake.IOperationResultDataInfo dataInfo, global::StrawberryShake.IEntityStoreSnapshot? snapshot) + { + return Create(dataInfo, snapshot); + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultInfoGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class GetBarsResultInfo : global::StrawberryShake.IOperationResultDataInfo + { + private readonly global::System.Collections.Generic.IReadOnlyCollection _entityIds; + private readonly global::System.UInt64 _version; + public GetBarsResultInfo(global::System.Collections.Generic.IReadOnlyList? bars, global::System.Collections.Generic.IReadOnlyCollection entityIds, global::System.UInt64 version) + { + Bars = bars; + _entityIds = entityIds ?? throw new global::System.ArgumentNullException(nameof(entityIds)); + _version = version; + } + + public global::System.Collections.Generic.IReadOnlyList? Bars + { + get; + } + + public global::System.Collections.Generic.IReadOnlyCollection EntityIds => _entityIds; + public global::System.UInt64 Version => _version; + public global::StrawberryShake.IOperationResultDataInfo WithVersion(global::System.UInt64 version) + { + return new GetBarsResultInfo(Bars, _entityIds, version); + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultFromEntityTypeMapperGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class GetBars_Bars_BarFromBarEntityMapper : global::StrawberryShake.IEntityMapper + { + private readonly global::StrawberryShake.IEntityStore _entityStore; + public GetBars_Bars_BarFromBarEntityMapper(global::StrawberryShake.IEntityStore entityStore) + { + _entityStore = entityStore ?? throw new global::System.ArgumentNullException(nameof(entityStore)); + } + + public GetBars_Bars_Bar Map(global::Foo.Bar.State.BarEntity entity, global::StrawberryShake.IEntityStoreSnapshot? snapshot = null) + { + if (snapshot is null) + { + snapshot = _entityStore.CurrentSnapshot; + } + + return new GetBars_Bars_Bar(entity.Id, entity.Name); + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultDataFactoryGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class SaveBarsResultFactory : global::StrawberryShake.IOperationResultDataFactory + { + private readonly global::StrawberryShake.IEntityStore _entityStore; + private readonly global::StrawberryShake.IEntityMapper _saveBars_SaveBar_BarFromBarEntityMapper; + public SaveBarsResultFactory(global::StrawberryShake.IEntityStore entityStore, global::StrawberryShake.IEntityMapper saveBars_SaveBar_BarFromBarEntityMapper) + { + _entityStore = entityStore ?? throw new global::System.ArgumentNullException(nameof(entityStore)); + _saveBars_SaveBar_BarFromBarEntityMapper = saveBars_SaveBar_BarFromBarEntityMapper ?? throw new global::System.ArgumentNullException(nameof(saveBars_SaveBar_BarFromBarEntityMapper)); + } + + global::System.Type global::StrawberryShake.IOperationResultDataFactory.ResultType => typeof(global::Foo.Bar.ISaveBarsResult); + public SaveBarsResult Create(global::StrawberryShake.IOperationResultDataInfo dataInfo, global::StrawberryShake.IEntityStoreSnapshot? snapshot = null) + { + if (snapshot is null) + { + snapshot = _entityStore.CurrentSnapshot; + } + + if (dataInfo is SaveBarsResultInfo info) + { + return new SaveBarsResult(MapISaveBars_SaveBar(info.SaveBar, snapshot)); + } + + throw new global::System.ArgumentException("SaveBarsResultInfo expected."); + } + + private global::Foo.Bar.ISaveBars_SaveBar? MapISaveBars_SaveBar(global::StrawberryShake.EntityId? entityId, global::StrawberryShake.IEntityStoreSnapshot snapshot) + { + if (entityId is null) + { + return null; + } + + if (entityId.Value.Name.Equals("Bar", global::System.StringComparison.Ordinal)) + { + return _saveBars_SaveBar_BarFromBarEntityMapper.Map(snapshot.GetEntity(entityId.Value) ?? throw new global::StrawberryShake.GraphQLClientException()); + } + + throw new global::System.NotSupportedException(); + } + + global::System.Object global::StrawberryShake.IOperationResultDataFactory.Create(global::StrawberryShake.IOperationResultDataInfo dataInfo, global::StrawberryShake.IEntityStoreSnapshot? snapshot) + { + return Create(dataInfo, snapshot); + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultInfoGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class SaveBarsResultInfo : global::StrawberryShake.IOperationResultDataInfo + { + private readonly global::System.Collections.Generic.IReadOnlyCollection _entityIds; + private readonly global::System.UInt64 _version; + public SaveBarsResultInfo(global::StrawberryShake.EntityId? saveBar, global::System.Collections.Generic.IReadOnlyCollection entityIds, global::System.UInt64 version) + { + SaveBar = saveBar; + _entityIds = entityIds ?? throw new global::System.ArgumentNullException(nameof(entityIds)); + _version = version; + } + + public global::StrawberryShake.EntityId? SaveBar + { + get; + } + + public global::System.Collections.Generic.IReadOnlyCollection EntityIds => _entityIds; + public global::System.UInt64 Version => _version; + public global::StrawberryShake.IOperationResultDataInfo WithVersion(global::System.UInt64 version) + { + return new SaveBarsResultInfo(SaveBar, _entityIds, version); + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.ResultFromEntityTypeMapperGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class SaveBars_SaveBar_BarFromBarEntityMapper : global::StrawberryShake.IEntityMapper + { + private readonly global::StrawberryShake.IEntityStore _entityStore; + public SaveBars_SaveBar_BarFromBarEntityMapper(global::StrawberryShake.IEntityStore entityStore) + { + _entityStore = entityStore ?? throw new global::System.ArgumentNullException(nameof(entityStore)); + } + + public SaveBars_SaveBar_Bar Map(global::Foo.Bar.State.BarEntity entity, global::StrawberryShake.IEntityStoreSnapshot? snapshot = null) + { + if (snapshot is null) + { + snapshot = _entityStore.CurrentSnapshot; + } + + return new SaveBars_SaveBar_Bar(entity.Id, entity.Name); + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.JsonResultBuilderGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class GetBarsBuilder : global::StrawberryShake.IOperationResultBuilder + { + private readonly global::StrawberryShake.IEntityStore _entityStore; + private readonly global::StrawberryShake.IEntityIdSerializer _idSerializer; + private readonly global::StrawberryShake.IOperationResultDataFactory _resultDataFactory; + private readonly global::StrawberryShake.Serialization.ILeafValueParser _stringParser; + public GetBarsBuilder(global::StrawberryShake.IEntityStore entityStore, global::StrawberryShake.IEntityIdSerializer idSerializer, global::StrawberryShake.IOperationResultDataFactory resultDataFactory, global::StrawberryShake.Serialization.ISerializerResolver serializerResolver) + { + _entityStore = entityStore ?? throw new global::System.ArgumentNullException(nameof(entityStore)); + _idSerializer = idSerializer ?? throw new global::System.ArgumentNullException(nameof(idSerializer)); + _resultDataFactory = resultDataFactory ?? throw new global::System.ArgumentNullException(nameof(resultDataFactory)); + _stringParser = serializerResolver.GetLeafValueParser("String") ?? throw new global::System.ArgumentException("No serializer for type `String` found."); + } + + public global::StrawberryShake.IOperationResult Build(global::StrawberryShake.Response response) + { + (IGetBarsResult Result, GetBarsResultInfo Info)? data = null; + global::System.Collections.Generic.IReadOnlyList? errors = null; + if (response.Exception is null) + { + try + { + if (response.Body != null) + { + if (response.Body.RootElement.TryGetProperty("data", out global::System.Text.Json.JsonElement dataElement) && dataElement.ValueKind == global::System.Text.Json.JsonValueKind.Object) + { + data = BuildData(dataElement); + } + + if (response.Body.RootElement.TryGetProperty("errors", out global::System.Text.Json.JsonElement errorsElement)) + { + errors = global::StrawberryShake.Json.JsonErrorParser.ParseErrors(errorsElement); + } + } + } + catch (global::System.Exception ex) + { + errors = new global::StrawberryShake.IClientError[]{new global::StrawberryShake.ClientError(ex.Message, exception: ex, extensions: new global::System.Collections.Generic.Dictionary{{"body", response.Body?.RootElement.ToString()}})}; + } + } + else + { + errors = new global::StrawberryShake.IClientError[]{new global::StrawberryShake.ClientError(response.Exception.Message, exception: response.Exception, extensions: new global::System.Collections.Generic.Dictionary{{"body", response.Body?.RootElement.ToString()}})}; + } + + return new global::StrawberryShake.OperationResult(data?.Result, data?.Info, _resultDataFactory, errors); + } + + private (IGetBarsResult, GetBarsResultInfo) BuildData(global::System.Text.Json.JsonElement obj) + { + var entityIds = new global::System.Collections.Generic.HashSet(); + global::StrawberryShake.IEntityStoreSnapshot snapshot = default !; + global::System.Collections.Generic.IReadOnlyList? barsId = default !; + _entityStore.Update(session => + { + barsId = UpdateIGetBars_BarsEntityArray(session, global::StrawberryShake.Json.JsonElementExtensions.GetPropertyOrNull(obj, "bars"), entityIds); + snapshot = session.CurrentSnapshot; + }); + var resultInfo = new GetBarsResultInfo(barsId, entityIds, snapshot.Version); + return (_resultDataFactory.Create(resultInfo), resultInfo); + } + + private global::System.Collections.Generic.IReadOnlyList? UpdateIGetBars_BarsEntityArray(global::StrawberryShake.IEntityStoreUpdateSession session, global::System.Text.Json.JsonElement? obj, global::System.Collections.Generic.ISet entityIds) + { + if (!obj.HasValue) + { + return null; + } + + var bars = new global::System.Collections.Generic.List(); + foreach (global::System.Text.Json.JsonElement child in obj.Value.EnumerateArray()) + { + bars.Add(UpdateIGetBars_BarsEntity(session, child, entityIds)); + } + + return bars; + } + + private global::StrawberryShake.EntityId? UpdateIGetBars_BarsEntity(global::StrawberryShake.IEntityStoreUpdateSession session, global::System.Text.Json.JsonElement? obj, global::System.Collections.Generic.ISet entityIds) + { + if (!obj.HasValue) + { + return null; + } + + global::StrawberryShake.EntityId entityId = _idSerializer.Parse(obj.Value); + entityIds.Add(entityId); + if (entityId.Name.Equals("Bar", global::System.StringComparison.Ordinal)) + { + if (session.CurrentSnapshot.TryGetEntity(entityId, out global::Foo.Bar.State.BarEntity? entity)) + { + session.SetEntity(entityId, new global::Foo.Bar.State.BarEntity(DeserializeNonNullableString(global::StrawberryShake.Json.JsonElementExtensions.GetPropertyOrNull(obj, "id")), DeserializeString(global::StrawberryShake.Json.JsonElementExtensions.GetPropertyOrNull(obj, "name")))); + } + else + { + session.SetEntity(entityId, new global::Foo.Bar.State.BarEntity(DeserializeNonNullableString(global::StrawberryShake.Json.JsonElementExtensions.GetPropertyOrNull(obj, "id")), DeserializeString(global::StrawberryShake.Json.JsonElementExtensions.GetPropertyOrNull(obj, "name")))); + } + + return entityId; + } + + throw new global::System.NotSupportedException(); + } + + private global::System.String DeserializeNonNullableString(global::System.Text.Json.JsonElement? obj) + { + if (!obj.HasValue) + { + throw new global::System.ArgumentNullException(); + } + + return _stringParser.Parse(obj.Value.GetString()!); + } + + private global::System.String? DeserializeString(global::System.Text.Json.JsonElement? obj) + { + if (!obj.HasValue) + { + return null; + } + + return _stringParser.Parse(obj.Value.GetString()!); + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.JsonResultBuilderGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class SaveBarsBuilder : global::StrawberryShake.IOperationResultBuilder + { + private readonly global::StrawberryShake.IEntityStore _entityStore; + private readonly global::StrawberryShake.IEntityIdSerializer _idSerializer; + private readonly global::StrawberryShake.IOperationResultDataFactory _resultDataFactory; + private readonly global::StrawberryShake.Serialization.ILeafValueParser _stringParser; + public SaveBarsBuilder(global::StrawberryShake.IEntityStore entityStore, global::StrawberryShake.IEntityIdSerializer idSerializer, global::StrawberryShake.IOperationResultDataFactory resultDataFactory, global::StrawberryShake.Serialization.ISerializerResolver serializerResolver) + { + _entityStore = entityStore ?? throw new global::System.ArgumentNullException(nameof(entityStore)); + _idSerializer = idSerializer ?? throw new global::System.ArgumentNullException(nameof(idSerializer)); + _resultDataFactory = resultDataFactory ?? throw new global::System.ArgumentNullException(nameof(resultDataFactory)); + _stringParser = serializerResolver.GetLeafValueParser("String") ?? throw new global::System.ArgumentException("No serializer for type `String` found."); + } + + public global::StrawberryShake.IOperationResult Build(global::StrawberryShake.Response response) + { + (ISaveBarsResult Result, SaveBarsResultInfo Info)? data = null; + global::System.Collections.Generic.IReadOnlyList? errors = null; + if (response.Exception is null) + { + try + { + if (response.Body != null) + { + if (response.Body.RootElement.TryGetProperty("data", out global::System.Text.Json.JsonElement dataElement) && dataElement.ValueKind == global::System.Text.Json.JsonValueKind.Object) + { + data = BuildData(dataElement); + } + + if (response.Body.RootElement.TryGetProperty("errors", out global::System.Text.Json.JsonElement errorsElement)) + { + errors = global::StrawberryShake.Json.JsonErrorParser.ParseErrors(errorsElement); + } + } + } + catch (global::System.Exception ex) + { + errors = new global::StrawberryShake.IClientError[]{new global::StrawberryShake.ClientError(ex.Message, exception: ex, extensions: new global::System.Collections.Generic.Dictionary{{"body", response.Body?.RootElement.ToString()}})}; + } + } + else + { + errors = new global::StrawberryShake.IClientError[]{new global::StrawberryShake.ClientError(response.Exception.Message, exception: response.Exception, extensions: new global::System.Collections.Generic.Dictionary{{"body", response.Body?.RootElement.ToString()}})}; + } + + return new global::StrawberryShake.OperationResult(data?.Result, data?.Info, _resultDataFactory, errors); + } + + private (ISaveBarsResult, SaveBarsResultInfo) BuildData(global::System.Text.Json.JsonElement obj) + { + var entityIds = new global::System.Collections.Generic.HashSet(); + global::StrawberryShake.IEntityStoreSnapshot snapshot = default !; + global::StrawberryShake.EntityId? saveBarId = default !; + _entityStore.Update(session => + { + saveBarId = UpdateISaveBars_SaveBarEntity(session, global::StrawberryShake.Json.JsonElementExtensions.GetPropertyOrNull(obj, "saveBar"), entityIds); + snapshot = session.CurrentSnapshot; + }); + var resultInfo = new SaveBarsResultInfo(saveBarId, entityIds, snapshot.Version); + return (_resultDataFactory.Create(resultInfo), resultInfo); + } + + private global::StrawberryShake.EntityId? UpdateISaveBars_SaveBarEntity(global::StrawberryShake.IEntityStoreUpdateSession session, global::System.Text.Json.JsonElement? obj, global::System.Collections.Generic.ISet entityIds) + { + if (!obj.HasValue) + { + return null; + } + + global::StrawberryShake.EntityId entityId = _idSerializer.Parse(obj.Value); + entityIds.Add(entityId); + if (entityId.Name.Equals("Bar", global::System.StringComparison.Ordinal)) + { + if (session.CurrentSnapshot.TryGetEntity(entityId, out global::Foo.Bar.State.BarEntity? entity)) + { + session.SetEntity(entityId, new global::Foo.Bar.State.BarEntity(DeserializeNonNullableString(global::StrawberryShake.Json.JsonElementExtensions.GetPropertyOrNull(obj, "id")), DeserializeString(global::StrawberryShake.Json.JsonElementExtensions.GetPropertyOrNull(obj, "name")))); + } + else + { + session.SetEntity(entityId, new global::Foo.Bar.State.BarEntity(DeserializeNonNullableString(global::StrawberryShake.Json.JsonElementExtensions.GetPropertyOrNull(obj, "id")), DeserializeString(global::StrawberryShake.Json.JsonElementExtensions.GetPropertyOrNull(obj, "name")))); + } + + return entityId; + } + + throw new global::System.NotSupportedException(); + } + + private global::System.String DeserializeNonNullableString(global::System.Text.Json.JsonElement? obj) + { + if (!obj.HasValue) + { + throw new global::System.ArgumentNullException(); + } + + return _stringParser.Parse(obj.Value.GetString()!); + } + + private global::System.String? DeserializeString(global::System.Text.Json.JsonElement? obj) + { + if (!obj.HasValue) + { + return null; + } + + return _stringParser.Parse(obj.Value.GetString()!); + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.EntityIdFactoryGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class FooClientEntityIdFactory : global::StrawberryShake.IEntityIdSerializer + { + private static readonly global::System.Text.Json.JsonWriterOptions _options = new global::System.Text.Json.JsonWriterOptions() + {Indented = false}; + public global::StrawberryShake.EntityId Parse(global::System.Text.Json.JsonElement obj) + { + global::System.String __typename = obj.GetProperty("__typename").GetString()!; + return __typename switch + { + "Bar" => ParseBarEntityId(obj, __typename), _ => throw new global::System.NotSupportedException()} + + ; + } + + public global::System.String Format(global::StrawberryShake.EntityId entityId) + { + return entityId.Name switch + { + "Bar" => FormatBarEntityId(entityId), _ => throw new global::System.NotSupportedException()} + + ; + } + + private global::StrawberryShake.EntityId ParseBarEntityId(global::System.Text.Json.JsonElement obj, global::System.String type) + { + return new global::StrawberryShake.EntityId(type, obj.GetProperty("id").GetString()!); + } + + private global::System.String FormatBarEntityId(global::StrawberryShake.EntityId entityId) + { + using var writer = new global::StrawberryShake.Internal.ArrayWriter(); + using var jsonWriter = new global::System.Text.Json.Utf8JsonWriter(writer, _options); + jsonWriter.WriteStartObject(); + jsonWriter.WriteString("__typename", entityId.Name); + jsonWriter.WriteString("id", (global::System.String)entityId.Value); + jsonWriter.WriteEndObject(); + jsonWriter.Flush(); + return global::System.Text.Encoding.UTF8.GetString(writer.GetInternalBuffer(), 0, writer.Length); + } + } + + // StrawberryShake.CodeGeneration.CSharp.Generators.StoreAccessorGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public partial class FooClientStoreAccessor : global::StrawberryShake.StoreAccessor + { + public FooClientStoreAccessor(global::StrawberryShake.IOperationStore operationStore, global::StrawberryShake.IEntityStore entityStore, global::StrawberryShake.IEntityIdSerializer entityIdSerializer, global::System.Collections.Generic.IEnumerable requestFactories, global::System.Collections.Generic.IEnumerable resultDataFactories): base(operationStore, entityStore, entityIdSerializer, requestFactories, resultDataFactories) + { + } + } +} + +namespace Microsoft.Extensions.DependencyInjection +{ + // StrawberryShake.CodeGeneration.CSharp.Generators.DependencyInjectionGenerator + [global::System.CodeDom.Compiler.GeneratedCode("StrawberryShake", "11.0.0")] + public static partial class FooClientServiceCollectionExtensions + { + public static global::StrawberryShake.IClientBuilder AddFooClient(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::StrawberryShake.ExecutionStrategy strategy = global::StrawberryShake.ExecutionStrategy.NetworkOnly) + { + var serviceCollection = new global::Microsoft.Extensions.DependencyInjection.ServiceCollection(); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => + { + ConfigureClientDefault(sp, serviceCollection, strategy); + return new ClientServiceProvider(global::Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(serviceCollection)); + }); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => new global::Foo.Bar.State.FooClientStoreAccessor(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp)), global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp)), global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp)), global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService>(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp)), global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService>(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp)))); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp))); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp))); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp))); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp))); + return new global::StrawberryShake.ClientBuilder("FooClient", services, serviceCollection); + } + + private static global::Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureClientDefault(global::System.IServiceProvider parentServices, global::Microsoft.Extensions.DependencyInjection.ServiceCollection services, global::StrawberryShake.ExecutionStrategy strategy = global::StrawberryShake.ExecutionStrategy.NetworkOnly) + { + global::Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.TryAddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.TryAddSingleton(services, sp => new global::StrawberryShake.OperationStore(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp))); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => + { + var clientFactory = global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(parentServices); + return new global::StrawberryShake.Transport.Http.HttpConnection(() => clientFactory.CreateClient("FooClient")); + }); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton, global::Foo.Bar.State.GetBars_Bars_BarFromBarEntityMapper>(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton, global::Foo.Bar.State.SaveBars_SaveBar_BarFromBarEntityMapper>(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => new global::StrawberryShake.Serialization.SerializerResolver(global::System.Linq.Enumerable.Concat(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService>(parentServices), global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService>(sp)))); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton, global::Foo.Bar.State.GetBarsResultFactory>(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService>(sp)); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp)); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton, global::Foo.Bar.State.GetBarsBuilder>(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, sp => new global::StrawberryShake.OperationExecutor(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp), () => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService>(sp), global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp), strategy)); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp)); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton, global::Foo.Bar.State.SaveBarsResultFactory>(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService>(sp)); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp)); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton, global::Foo.Bar.State.SaveBarsBuilder>(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, sp => new global::StrawberryShake.OperationExecutor(global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp), () => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService>(sp), global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp), strategy)); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp)); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(services, sp => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(sp)); + return services; + } + + private class ClientServiceProvider : System.IServiceProvider, System.IDisposable + { + private readonly System.IServiceProvider _provider; + public ClientServiceProvider(System.IServiceProvider provider) + { + _provider = provider; + } + + public object? GetService(System.Type serviceType) + { + return _provider.GetService(serviceType); + } + + public void Dispose() + { + if (_provider is System.IDisposable d) + { + d.Dispose(); + } + } + } + } +} + + diff --git a/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Tests/StrawberryShake.CodeGeneration.Tests.csproj b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Tests/StrawberryShake.CodeGeneration.Tests.csproj index 21147007985..12a7434cb31 100644 --- a/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Tests/StrawberryShake.CodeGeneration.Tests.csproj +++ b/src/StrawberryShake/CodeGeneration/test/CodeGeneration.Tests/StrawberryShake.CodeGeneration.Tests.csproj @@ -19,21 +19,6 @@ Always - - Always - - - Always - - - Always - - - Always - - - Always - diff --git a/src/StrawberryShake/CodeGeneration/test/Directory.Build.props b/src/StrawberryShake/CodeGeneration/test/Directory.Build.props index 07adac89232..97384b48534 100644 --- a/src/StrawberryShake/CodeGeneration/test/Directory.Build.props +++ b/src/StrawberryShake/CodeGeneration/test/Directory.Build.props @@ -9,7 +9,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/StrawberryShake/SourceGenerator/src/CodeGeneration.CSharp.Analyzers/CSharpClientGenerator.cs b/src/StrawberryShake/SourceGenerator/src/CodeGeneration.CSharp.Analyzers/CSharpClientGenerator.cs index 28db0ed5578..eca18007fca 100644 --- a/src/StrawberryShake/SourceGenerator/src/CodeGeneration.CSharp.Analyzers/CSharpClientGenerator.cs +++ b/src/StrawberryShake/SourceGenerator/src/CodeGeneration.CSharp.Analyzers/CSharpClientGenerator.cs @@ -223,6 +223,7 @@ private bool TryGenerateClient( StrictSchemaValidation = context.Settings.StrictSchemaValidation, NoStore = context.Settings.NoStore, InputRecords = context.Settings.Records.Inputs, + RazorComponents = context.Settings.RazorComponents, EntityRecords = context.Settings.Records.Entities, SingleCodeFile = context.Settings.UseSingleFile, HashProvider = context.Settings.HashAlgorithm.ToLowerInvariant() switch @@ -293,15 +294,16 @@ private static bool EnsurePreconditionsAreMet( const string http = "StrawberryShake.Transport.Http"; const string websockets = "StrawberryShake.Transport.WebSockets"; const string inmemory = "StrawberryShake.Transport.InMemory"; + const string razor = "StrawberryShake.Razor"; if (settings.TransportProfiles.Count == 1) { - StrawberryShakeTransportProfile transportProfile = settings.TransportProfiles[0]; + StrawberryShakeSettingsTransportProfile settingsTransportProfile = settings.TransportProfiles[0]; - if (transportProfile.Default == TransportType.Http && - transportProfile.Subscription == TransportType.WebSocket && - transportProfile.Query == null && - transportProfile.Mutation == null) + if (settingsTransportProfile.Default == TransportType.Http && + settingsTransportProfile.Subscription == TransportType.WebSocket && + settingsTransportProfile.Query == null && + settingsTransportProfile.Mutation == null) { if (!EnsureDependencyExists(context, http)) { @@ -346,6 +348,14 @@ private static bool EnsurePreconditionsAreMet( } } + if (settings.RazorComponents) + { + if (!EnsureDependencyExists(context, razor)) + { + return false; + } + } + return true; } diff --git a/src/StrawberryShake/SourceGenerator/src/CodeGeneration.CSharp.Analyzers/StrawberryShake.CodeGeneration.CSharp.Analyzers.csproj b/src/StrawberryShake/SourceGenerator/src/CodeGeneration.CSharp.Analyzers/StrawberryShake.CodeGeneration.CSharp.Analyzers.csproj index 79fdf9ad984..740e1d88719 100644 --- a/src/StrawberryShake/SourceGenerator/src/CodeGeneration.CSharp.Analyzers/StrawberryShake.CodeGeneration.CSharp.Analyzers.csproj +++ b/src/StrawberryShake/SourceGenerator/src/CodeGeneration.CSharp.Analyzers/StrawberryShake.CodeGeneration.CSharp.Analyzers.csproj @@ -21,7 +21,7 @@ - + diff --git a/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/CustomScalar/.generated/CustomScalarClient.StrawberryShake.cs b/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/CustomScalar/.generated/CustomScalarClient.StrawberryShake.cs index 5f04c670818..3ad81ad6130 100644 --- a/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/CustomScalar/.generated/CustomScalarClient.StrawberryShake.cs +++ b/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/CustomScalar/.generated/CustomScalarClient.StrawberryShake.cs @@ -144,44 +144,44 @@ public GetCustomValueResult(global::StrawberryShake.CodeGeneration.CSharp.Analyz public global::StrawberryShake.CodeGeneration.CSharp.Analyzers.Tests.Custom? CustomScalar { get; } - public override global::System.Boolean Equals(global::System.Object? obj) + public virtual global::System.Boolean Equals(GetCustomValueResult? other) { - if (ReferenceEquals(null, obj)) + if (ReferenceEquals(null, other)) { return false; } - if (ReferenceEquals(this, obj)) + if (ReferenceEquals(this, other)) { return true; } - if (obj.GetType() != GetType()) + if (other.GetType() != GetType()) { return false; } - return Equals((GetCustomValueResult)obj); + return (((CustomScalar is null && other.CustomScalar is null) || CustomScalar != null && CustomScalar.Equals(other.CustomScalar))); } - public global::System.Boolean Equals(GetCustomValueResult? other) + public override global::System.Boolean Equals(global::System.Object? obj) { - if (ReferenceEquals(null, other)) + if (ReferenceEquals(null, obj)) { return false; } - if (ReferenceEquals(this, other)) + if (ReferenceEquals(this, obj)) { return true; } - if (other.GetType() != GetType()) + if (obj.GetType() != GetType()) { return false; } - return (((CustomScalar is null && other.CustomScalar is null) || CustomScalar != null && CustomScalar.Equals(other.CustomScalar))); + return Equals((GetCustomValueResult)obj); } public override global::System.Int32 GetHashCode() diff --git a/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/StarWars/.generated/StarWarsClient.StrawberryShake.cs b/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/StarWars/.generated/StarWarsClient.StrawberryShake.cs index 8a14d82661e..e088665a837 100644 --- a/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/StarWars/.generated/StarWarsClient.StrawberryShake.cs +++ b/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/StarWars/.generated/StarWarsClient.StrawberryShake.cs @@ -149,44 +149,44 @@ public GetPeopleResult(global::StrawberryShake.CodeGeneration.CSharp.Analyzers.T /// public global::StrawberryShake.CodeGeneration.CSharp.Analyzers.Tests.IGetPeople_People? People { get; } - public override global::System.Boolean Equals(global::System.Object? obj) + public virtual global::System.Boolean Equals(GetPeopleResult? other) { - if (ReferenceEquals(null, obj)) + if (ReferenceEquals(null, other)) { return false; } - if (ReferenceEquals(this, obj)) + if (ReferenceEquals(this, other)) { return true; } - if (obj.GetType() != GetType()) + if (other.GetType() != GetType()) { return false; } - return Equals((GetPeopleResult)obj); + return (((People is null && other.People is null) || People != null && People.Equals(other.People))); } - public global::System.Boolean Equals(GetPeopleResult? other) + public override global::System.Boolean Equals(global::System.Object? obj) { - if (ReferenceEquals(null, other)) + if (ReferenceEquals(null, obj)) { return false; } - if (ReferenceEquals(this, other)) + if (ReferenceEquals(this, obj)) { return true; } - if (other.GetType() != GetType()) + if (obj.GetType() != GetType()) { return false; } - return (((People is null && other.People is null) || People != null && People.Equals(other.People))); + return Equals((GetPeopleResult)obj); } public override global::System.Int32 GetHashCode() @@ -221,44 +221,44 @@ public GetPeople_People_PersonConnection(global::System.Collections.Generic.IRea /// public global::System.Collections.Generic.IReadOnlyList? Nodes { get; } - public override global::System.Boolean Equals(global::System.Object? obj) + public virtual global::System.Boolean Equals(GetPeople_People_PersonConnection? other) { - if (ReferenceEquals(null, obj)) + if (ReferenceEquals(null, other)) { return false; } - if (ReferenceEquals(this, obj)) + if (ReferenceEquals(this, other)) { return true; } - if (obj.GetType() != GetType()) + if (other.GetType() != GetType()) { return false; } - return Equals((GetPeople_People_PersonConnection)obj); + return (global::StrawberryShake.Helper.ComparisonHelper.SequenceEqual(Nodes, other.Nodes)); } - public global::System.Boolean Equals(GetPeople_People_PersonConnection? other) + public override global::System.Boolean Equals(global::System.Object? obj) { - if (ReferenceEquals(null, other)) + if (ReferenceEquals(null, obj)) { return false; } - if (ReferenceEquals(this, other)) + if (ReferenceEquals(this, obj)) { return true; } - if (other.GetType() != GetType()) + if (obj.GetType() != GetType()) { return false; } - return (global::StrawberryShake.Helper.ComparisonHelper.SequenceEqual(Nodes, other.Nodes)); + return Equals((GetPeople_People_PersonConnection)obj); } public override global::System.Int32 GetHashCode() @@ -302,44 +302,44 @@ public GetPeople_People_Nodes_Person(global::System.String name, global::System. public global::System.DateTimeOffset LastSeen { get; } - public override global::System.Boolean Equals(global::System.Object? obj) + public virtual global::System.Boolean Equals(GetPeople_People_Nodes_Person? other) { - if (ReferenceEquals(null, obj)) + if (ReferenceEquals(null, other)) { return false; } - if (ReferenceEquals(this, obj)) + if (ReferenceEquals(this, other)) { return true; } - if (obj.GetType() != GetType()) + if (other.GetType() != GetType()) { return false; } - return Equals((GetPeople_People_Nodes_Person)obj); + return (Name.Equals(other.Name)) && Email.Equals(other.Email) && IsOnline == other.IsOnline && LastSeen.Equals(other.LastSeen); } - public global::System.Boolean Equals(GetPeople_People_Nodes_Person? other) + public override global::System.Boolean Equals(global::System.Object? obj) { - if (ReferenceEquals(null, other)) + if (ReferenceEquals(null, obj)) { return false; } - if (ReferenceEquals(this, other)) + if (ReferenceEquals(this, obj)) { return true; } - if (other.GetType() != GetType()) + if (obj.GetType() != GetType()) { return false; } - return (Name.Equals(other.Name)) && Email.Equals(other.Email) && IsOnline == other.IsOnline && LastSeen.Equals(other.LastSeen); + return Equals((GetPeople_People_Nodes_Person)obj); } public override global::System.Int32 GetHashCode() @@ -751,24 +751,31 @@ public GetPeopleBuilder(global::StrawberryShake.IEntityStore entityStore, global { (IGetPeopleResult Result, GetPeopleResultInfo Info)? data = null; global::System.Collections.Generic.IReadOnlyList? errors = null; - try + if (response.Exception is null) { - if (response.Body != null) + try { - if (response.Body.RootElement.TryGetProperty("data", out global::System.Text.Json.JsonElement dataElement) && dataElement.ValueKind == global::System.Text.Json.JsonValueKind.Object) + if (response.Body != null) { - data = BuildData(dataElement); - } + if (response.Body.RootElement.TryGetProperty("data", out global::System.Text.Json.JsonElement dataElement) && dataElement.ValueKind == global::System.Text.Json.JsonValueKind.Object) + { + data = BuildData(dataElement); + } - if (response.Body.RootElement.TryGetProperty("errors", out global::System.Text.Json.JsonElement errorsElement)) - { - errors = global::StrawberryShake.Json.JsonErrorParser.ParseErrors(errorsElement); + if (response.Body.RootElement.TryGetProperty("errors", out global::System.Text.Json.JsonElement errorsElement)) + { + errors = global::StrawberryShake.Json.JsonErrorParser.ParseErrors(errorsElement); + } } } + catch (global::System.Exception ex) + { + errors = new global::StrawberryShake.IClientError[]{new global::StrawberryShake.ClientError(ex.Message, exception: ex, extensions: new global::System.Collections.Generic.Dictionary{{"body", response.Body?.RootElement.ToString()}})}; + } } - catch (global::System.Exception ex) + else { - errors = new global::StrawberryShake.IClientError[]{new global::StrawberryShake.ClientError(ex.Message, exception: ex)}; + errors = new global::StrawberryShake.IClientError[]{new global::StrawberryShake.ClientError(response.Exception.Message, exception: response.Exception, extensions: new global::System.Collections.Generic.Dictionary{{"body", response.Body?.RootElement.ToString()}})}; } return new global::StrawberryShake.OperationResult(data?.Result, data?.Info, _resultDataFactory, errors); diff --git a/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/StrawberryShake.CodeGeneration.CSharp.Analyzers.Tests.csproj b/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/StrawberryShake.CodeGeneration.CSharp.Analyzers.Tests.csproj index 3f32ca91cb4..1f67caed575 100644 --- a/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/StrawberryShake.CodeGeneration.CSharp.Analyzers.Tests.csproj +++ b/src/StrawberryShake/SourceGenerator/test/CodeGeneration.CSharp.Analyzers.Tests/StrawberryShake.CodeGeneration.CSharp.Analyzers.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/StrawberryShake/Tooling/src/Configuration/GraphQLConfig.cs b/src/StrawberryShake/Tooling/src/Configuration/GraphQLConfig.cs index 2c8db61fddf..b288d9b21ab 100644 --- a/src/StrawberryShake/Tooling/src/Configuration/GraphQLConfig.cs +++ b/src/StrawberryShake/Tooling/src/Configuration/GraphQLConfig.cs @@ -21,7 +21,7 @@ public override string ToString() if (Extensions.StrawberryShake.TransportProfiles.Count == 0) { Extensions.StrawberryShake.TransportProfiles.Add( - new StrawberryShakeTransportProfile + new StrawberryShakeSettingsTransportProfile { Default = TransportType.Http, Subscription = TransportType.WebSocket @@ -47,7 +47,7 @@ public static GraphQLConfig FromJson(string json) if (config.Extensions.StrawberryShake.TransportProfiles.Count == 0) { config.Extensions.StrawberryShake.TransportProfiles.Add( - new StrawberryShakeTransportProfile + new StrawberryShakeSettingsTransportProfile { Default = TransportType.Http, Subscription = TransportType.WebSocket diff --git a/src/StrawberryShake/Tooling/src/Configuration/StrawberryShakeSettings.cs b/src/StrawberryShake/Tooling/src/Configuration/StrawberryShakeSettings.cs index 9b70bb17e22..621d660b45d 100644 --- a/src/StrawberryShake/Tooling/src/Configuration/StrawberryShakeSettings.cs +++ b/src/StrawberryShake/Tooling/src/Configuration/StrawberryShakeSettings.cs @@ -2,31 +2,75 @@ namespace StrawberryShake.Tools.Configuration { + /// + /// The Strawberry Shake generator settings. + /// public class StrawberryShakeSettings { + /// + /// Gets or sets the name of the client. + /// public string Name { get; set; } = "Client"; + /// + /// Gets or sets the namespace of the client. + /// public string? Namespace { get; set; } + /// + /// Gets or sets the Url to update the schema files. + /// public string? Url { get; set; } + /// + /// Defines if the generator shall generate dependency injection code. + /// public bool DependencyInjection { get; set; } = true; + /// + /// Defines if the generator shall validate the schema. + /// public bool StrictSchemaValidation { get; set; } = true; + /// + /// Gets or sets the persisted query hash algorithm. + /// public string HashAlgorithm { get; set; } = "md5"; + /// + /// Defines that only a single code file shall be generated. + /// public bool UseSingleFile { get; set; } = true; + /// + /// Defines the default request strategy. + /// public RequestStrategy RequestStrategy { get; set; } = RequestStrategy.Default; + /// + /// Gets or sets the name of the generated code output directory. + /// public string OutputDirectoryName { get; set; } = "Generated"; + /// + /// Defines if a client shall be generated without a store. + /// public bool NoStore { get; set; } = false; + /// + /// Defines if the generated code shall be emitted. + /// public bool EmitGeneratedCode { get; set; } = true; + /// + /// Defines if the generator shall generate blazor query components. + /// + public bool RazorComponents { get; set; } = false; + + /// + /// Gets the record generator settings. + /// public StrawberryShakeSettingsRecords Records { get; } = new() { @@ -34,6 +78,9 @@ public class StrawberryShakeSettings Entities = false }; - public List TransportProfiles { get; } = new(); + /// + /// Gets the transport profiles. + /// + public List TransportProfiles { get; } = new(); } } diff --git a/src/StrawberryShake/Tooling/src/Configuration/StrawberryShakeTransportProfile.cs b/src/StrawberryShake/Tooling/src/Configuration/StrawberryShakeSettingsTransportProfile.cs similarity index 93% rename from src/StrawberryShake/Tooling/src/Configuration/StrawberryShakeTransportProfile.cs rename to src/StrawberryShake/Tooling/src/Configuration/StrawberryShakeSettingsTransportProfile.cs index 048a9efba76..51b534ccb6a 100644 --- a/src/StrawberryShake/Tooling/src/Configuration/StrawberryShakeTransportProfile.cs +++ b/src/StrawberryShake/Tooling/src/Configuration/StrawberryShakeSettingsTransportProfile.cs @@ -2,7 +2,7 @@ namespace StrawberryShake.Tools.Configuration { - public class StrawberryShakeTransportProfile + public class StrawberryShakeSettingsTransportProfile { public string Name { get; set; } = default!; diff --git a/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json.snap b/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json.snap index 8b9a32379f0..0951298463e 100644 --- a/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json.snap +++ b/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json.snap @@ -15,6 +15,7 @@ "OutputDirectoryName": "Generated", "NoStore": false, "EmitGeneratedCode": true, + "RazorComponents": false, "Records": { "Inputs": false, "Entities": false diff --git a/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json_With_Records.snap b/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json_With_Records.snap index bfaec00a290..0d18569ec71 100644 --- a/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json_With_Records.snap +++ b/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json_With_Records.snap @@ -15,6 +15,7 @@ "OutputDirectoryName": "Generated", "NoStore": false, "EmitGeneratedCode": true, + "RazorComponents": false, "Records": { "Inputs": true, "Entities": true diff --git a/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json_With_Transport_Profiles.snap b/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json_With_Transport_Profiles.snap index 41b4eb654d2..de75515252b 100644 --- a/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json_With_Transport_Profiles.snap +++ b/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Load_Json_With_Transport_Profiles.snap @@ -15,6 +15,7 @@ "OutputDirectoryName": "Generated", "NoStore": false, "EmitGeneratedCode": true, + "RazorComponents": false, "Records": { "Inputs": false, "Entities": false diff --git a/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Save_Default_Config.snap b/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Save_Default_Config.snap index dc36aa971af..c67863eb904 100644 --- a/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Save_Default_Config.snap +++ b/src/StrawberryShake/Tooling/test/Configuration.Tests/__snapshots__/GraphQLConfigTests.Save_Default_Config.snap @@ -12,6 +12,7 @@ "outputDirectoryName": "Generated", "noStore": false, "emitGeneratedCode": true, + "razorComponents": false, "records": { "inputs": false, "entities": false