private static ICode GenerateInternalMethodBody( CSharpSyntaxGeneratorSettings settings, DependencyInjectionDescriptor descriptor, TransportProfile profile) { var rootNamespace = descriptor.ClientDescriptor.RuntimeType.Namespace; var hasSubscriptions = descriptor.Operations.OfType <SubscriptionOperationDescriptor>().Any(); var hasQueries = descriptor.Operations.OfType <QueryOperationDescriptor>().Any(); var hasMutations = descriptor.Operations.OfType <MutationOperationDescriptor>().Any(); CodeBlockBuilder body = CodeBlockBuilder .New() .AddCode(CreateBaseCode(settings)); var generatedConnections = new HashSet <TransportType>(); if (hasSubscriptions) { generatedConnections.Add(profile.Subscription); body.AddCode( RegisterConnection(profile.Subscription, descriptor.Name)); } if (hasQueries && !generatedConnections.Contains(profile.Query)) { generatedConnections.Add(profile.Query); body.AddCode(RegisterConnection(profile.Query, descriptor.Name)); } if (hasMutations && !generatedConnections.Contains(profile.Mutation)) { generatedConnections.Add(profile.Mutation); body.AddCode(RegisterConnection(profile.Mutation, descriptor.Name)); } body.AddEmptyLine(); foreach (var typeDescriptor in descriptor.TypeDescriptors .OfType <INamedTypeDescriptor>()) { if (typeDescriptor.Kind == TypeKind.Entity && !typeDescriptor.IsInterface()) { INamedTypeDescriptor namedTypeDescriptor = (INamedTypeDescriptor)typeDescriptor.NamedType(); NameString className = namedTypeDescriptor.ExtractMapperName(); var interfaceName = TypeNames.IEntityMapper.WithGeneric( namedTypeDescriptor.ExtractType().ToString(), $"{rootNamespace}.{typeDescriptor.RuntimeType.Name}"); body.AddMethodCall() .SetMethodName(TypeNames.AddSingleton) .AddGeneric(interfaceName) .AddGeneric($"{CreateStateNamespace(rootNamespace)}.{className}") .AddArgument(_services); } } body.AddEmptyLine(); foreach (var enumType in descriptor.EnumTypeDescriptor) { body.AddMethodCall() .SetMethodName(TypeNames.AddSingleton) .AddGeneric(TypeNames.ISerializer) .AddGeneric(CreateEnumParserName($"{rootNamespace}.{enumType.Name}")) .AddArgument(_services); } foreach (var serializer in _serializers) { body.AddMethodCall() .SetMethodName(TypeNames.AddSingleton) .AddGeneric(TypeNames.ISerializer) .AddGeneric(serializer) .AddArgument(_services); } RuntimeTypeInfo stringTypeInfo = new RuntimeTypeInfo(TypeNames.String); foreach (var scalar in descriptor.TypeDescriptors.OfType <ScalarTypeDescriptor>()) { if (scalar.RuntimeType.Equals(stringTypeInfo) && scalar.SerializationType.Equals(stringTypeInfo) && !BuiltInScalarNames.IsBuiltInScalar(scalar.Name)) { body.AddMethodCall() .SetMethodName(TypeNames.AddSingleton) .AddGeneric(TypeNames.ISerializer) .AddArgument(_services) .AddArgument(MethodCallBuilder .Inline() .SetNew() .SetMethodName(TypeNames.StringSerializer) .AddArgument(scalar.Name.AsStringToken())); } } foreach (var inputTypeDescriptor in descriptor.TypeDescriptors .Where(x => x.Kind is TypeKind.Input)) { var formatter = CreateInputValueFormatter( (InputObjectTypeDescriptor)inputTypeDescriptor.NamedType()); body.AddMethodCall() .SetMethodName(TypeNames.AddSingleton) .AddGeneric(TypeNames.ISerializer) .AddGeneric($"{rootNamespace}.{formatter}") .AddArgument(_services); } body.AddCode(RegisterSerializerResolver()); body.AddEmptyLine(); foreach (var operation in descriptor.Operations) { if (!(operation.ResultTypeReference is InterfaceTypeDescriptor typeDescriptor)) { continue; } TransportType operationKind = operation switch { SubscriptionOperationDescriptor => profile.Subscription, QueryOperationDescriptor => profile.Query, MutationOperationDescriptor => profile.Mutation, _ => throw ThrowHelper.DependencyInjection_InvalidOperationKind(operation) }; string connectionKind = operationKind switch { TransportType.Http => TypeNames.IHttpConnection, TransportType.WebSocket => TypeNames.IWebSocketConnection, TransportType.InMemory => TypeNames.IInMemoryConnection, { } v => throw ThrowHelper.DependencyInjection_InvalidTransportType(v) }; string operationName = operation.Name; string fullName = operation.RuntimeType.ToString(); string operationInterfaceName = operation.InterfaceType.ToString(); string resultInterface = typeDescriptor.RuntimeType.ToString(); // The factories are generated based on the concrete result type, which is the // only implementee of the result type interface. var factoryName = CreateResultFactoryName( typeDescriptor.ImplementedBy.First().RuntimeType.Name); var builderName = CreateResultBuilderName(operationName); body.AddCode( RegisterOperation( settings, connectionKind, fullName, operationInterfaceName, resultInterface, $"{CreateStateNamespace(operation.RuntimeType.Namespace)}.{factoryName}", $"{CreateStateNamespace(operation.RuntimeType.Namespace)}.{builderName}")); } if (settings.IsStoreEnabled()) { body.AddCode( MethodCallBuilder .New() .SetMethodName(TypeNames.AddSingleton) .AddGeneric(TypeNames.IEntityIdSerializer) .AddGeneric(descriptor.EntityIdFactoryDescriptor.Type.ToString()) .AddArgument(_services)); } body.AddCode( MethodCallBuilder .New() .SetMethodName(TypeNames.AddSingleton) .AddGeneric(descriptor.ClientDescriptor.RuntimeType.ToString()) .AddArgument(_services)); body.AddCode( MethodCallBuilder .New() .SetMethodName(TypeNames.AddSingleton) .AddGeneric(descriptor.ClientDescriptor.InterfaceType.ToString()) .AddArgument(_services) .AddArgument(LambdaBuilder .New() .AddArgument(_sp) .SetCode(MethodCallBuilder .Inline() .SetMethodName(TypeNames.GetRequiredService) .AddGeneric(descriptor.ClientDescriptor.RuntimeType.ToString()) .AddArgument(_sp)))); body.AddLine($"return {_services};"); return(body); }
private void AddBuildDataMethod( CSharpSyntaxGeneratorSettings settings, InterfaceTypeDescriptor resultNamedType, ClassBuilder classBuilder) { var concreteType = CreateResultInfoName( resultNamedType.ImplementedBy.First().RuntimeType.Name); MethodBuilder buildDataMethod = classBuilder .AddMethod() .SetPrivate() .SetName("BuildData") .SetReturnType($"({resultNamedType.RuntimeType.Name}, {concreteType})") .AddParameter(_obj, x => x.SetType(TypeNames.JsonElement)); if (settings.IsStoreEnabled()) { buildDataMethod.AddCode( AssignmentBuilder .New() .SetLefthandSide($"var {_entityIds}") .SetRighthandSide(MethodCallBuilder .Inline() .SetNew() .SetMethodName(TypeNames.HashSet) .AddGeneric(TypeNames.EntityId))) .AddCode( AssignmentBuilder .New() .SetLefthandSide($"{TypeNames.IEntityStoreSnapshot} {_snapshot}") .SetRighthandSide("default!")); } buildDataMethod.AddEmptyLine(); CodeBlockBuilder storeUpdateBody = CodeBlockBuilder.New(); if (settings.IsStoreEnabled()) { foreach (PropertyDescriptor property in resultNamedType.Properties.Where(prop => prop.Type.IsOrContainsEntity())) { var variableName = $"{GetParameterName(property.Name)}Id"; buildDataMethod .AddCode(AssignmentBuilder .New() .SetLefthandSide(CodeBlockBuilder .New() .AddCode(property.Type.ToStateTypeReference()) .AddCode(variableName)) .SetRighthandSide("default!")); storeUpdateBody .AddCode(AssignmentBuilder .New() .SetLefthandSide(variableName) .SetRighthandSide(BuildUpdateMethodCall(property))); } storeUpdateBody .AddEmptyLine() .AddCode(AssignmentBuilder .New() .SetLefthandSide(_snapshot) .SetRighthandSide($"{_session}.CurrentSnapshot")); buildDataMethod .AddCode(MethodCallBuilder .New() .SetMethodName(_entityStore, "Update") .AddArgument(LambdaBuilder .New() .AddArgument(_session) .SetBlock(true) .SetCode(storeUpdateBody))); } buildDataMethod .AddEmptyLine() .AddCode( AssignmentBuilder .New() .SetLefthandSide($"var {_resultInfo}") .SetRighthandSide( CreateResultInfoMethodCall(settings, resultNamedType, concreteType))) .AddEmptyLine() .AddCode( TupleBuilder .Inline() .SetDetermineStatement(true) .SetReturn() .AddMember(MethodCallBuilder .Inline() .SetMethodName(_resultDataFactory, "Create") .AddArgument(_resultInfo)) .AddMember(_resultInfo)); }