public static TypeReferenceBuilder ToTypeReference( this ITypeDescriptor typeReferenceDescriptor, TypeReferenceBuilder?builder = null) { TypeReferenceBuilder actualBuilder = builder ?? TypeReferenceBuilder.New(); if (typeReferenceDescriptor is NonNullTypeDescriptor n) { typeReferenceDescriptor = n.InnerType; } else { actualBuilder.SetIsNullable(true); } return(typeReferenceDescriptor switch { ListTypeDescriptor list => ToTypeReference(list.InnerType, actualBuilder.SetListType()), EnumTypeDescriptor @enum => actualBuilder.SetName(@enum.RuntimeType.ToString()), ILeafTypeDescriptor leaf => actualBuilder.SetName(leaf.RuntimeType.ToString()), INamedTypeDescriptor named => actualBuilder.SetName(named.RuntimeType.ToString()), _ => throw new ArgumentOutOfRangeException(nameof(typeReferenceDescriptor)) });
public static TypeReferenceBuilder ToEntityIdBuilder( this ITypeDescriptor typeDescriptor, TypeReferenceBuilder?builder = null, bool isNonNull = false) { TypeReferenceBuilder actualBuilder = builder ?? TypeReferenceBuilder.New(); switch (typeDescriptor) { case ListTypeDescriptor listTypeDescriptor: actualBuilder.SetIsNullable(!isNonNull); actualBuilder.SetListType(); ToEntityIdBuilder( listTypeDescriptor.InnerType, actualBuilder); break; case NamedTypeDescriptor namedTypeDescriptor: actualBuilder.SetIsNullable(!isNonNull); if (namedTypeDescriptor.IsLeafType() && !namedTypeDescriptor.IsEnum) { actualBuilder.SetName( $"{namedTypeDescriptor.Namespace}.{namedTypeDescriptor.Name}"); } else if (namedTypeDescriptor.IsDataType()) { actualBuilder.SetName( namedTypeDescriptor.Kind == TypeKind.ComplexDataType ? $"global::{namedTypeDescriptor.Namespace}.State.I" + DataTypeNameFromTypeName( namedTypeDescriptor.ComplexDataTypeParent !) : $"global::{namedTypeDescriptor.Namespace}.State." + DataTypeNameFromTypeName( namedTypeDescriptor.GraphQLTypeName !)); } else if (namedTypeDescriptor.IsEntityType()) { actualBuilder.SetName(TypeNames.EntityId); } else { actualBuilder.SetName(typeDescriptor.Name); } break; case NonNullTypeDescriptor nonNullTypeDescriptor: ToEntityIdBuilder( nonNullTypeDescriptor.InnerType, actualBuilder, true); break; default: throw new ArgumentOutOfRangeException(nameof(typeDescriptor)); } return(actualBuilder); }
private void AddBuildMethod( InterfaceTypeDescriptor resultNamedType, ClassBuilder classBuilder) { var responseParameterName = "response"; var buildMethod = MethodBuilder .New() .SetAccessModifier(AccessModifier.Public) .SetName("Build") .SetReturnType( TypeReferenceBuilder.New() .SetName(TypeNames.IOperationResult) .AddGeneric(resultNamedType.RuntimeType.Name)) .AddParameter( ParameterBuilder.New() .SetType( TypeReferenceBuilder.New() .SetName(TypeNames.Response) .AddGeneric(TypeNames.JsonDocument) .SetName(TypeNames.Response)) .SetName(responseParameterName)); var concreteResultType = CreateResultInfoName(resultNamedType.ImplementedBy.First().RuntimeType.Name); buildMethod.AddCode( AssignmentBuilder.New() .SetLefthandSide( $"({resultNamedType.RuntimeType.Name} Result, {concreteResultType} " + "Info)? data") .SetRighthandSide("null")); buildMethod.AddEmptyLine(); buildMethod.AddCode( IfBuilder.New() .SetCondition( ConditionBuilder.New() .Set("response.Body is not null") .And("response.Body.RootElement.TryGetProperty(\"data\"," + $" out {TypeNames.JsonElement} obj)")) .AddCode("data = BuildData(obj);")); buildMethod.AddEmptyLine(); buildMethod.AddCode( MethodCallBuilder.New() .SetPrefix("return new ") .SetMethodName( TypeNames.OperationResult.WithGeneric(resultNamedType.RuntimeType.Name)) .AddArgument("data?.Result") .AddArgument("data?.Info") .AddArgument(_resultDataFactoryFieldName) .AddArgument("null")); classBuilder.AddMethod(buildMethod); }
protected override void Generate( CodeWriter writer, OperationDescriptor operationDescriptor, out string fileName) { var(classBuilder, constructorBuilder) = CreateClassBuilder(); fileName = operationDescriptor.Name; classBuilder.SetName(fileName); constructorBuilder.SetTypeName(fileName); var resultTypeReference = (INamedTypeDescriptor)operationDescriptor.ResultTypeReference.NamedType(); AddConstructorAssignedField( TypeReferenceBuilder.New() .SetName(TypeNames.IOperationExecutor) .AddGeneric(resultTypeReference.RuntimeType.Name), OperationExecutorFieldName, classBuilder, constructorBuilder); var neededSerializers = operationDescriptor.Arguments .ToLookup(x => x.Type.Name) .Select(x => x.First()) .ToDictionary(x => x.Type.Name); if (neededSerializers.Any()) { constructorBuilder .AddParameter( "serializerResolver", x => x.SetType(TypeNames.ISerializerResolver)); foreach (var property in neededSerializers.Values) { if (property.Type.GetName().Value is { } name) { MethodCallBuilder call = MethodCallBuilder.New() .SetMethodName("serializerResolver." + nameof(ISerializerResolver.GetInputValueFormatter)) .AddArgument(name.AsStringToken() ?? "") .SetPrefix($"{GetFieldName(name)}Formatter = "); constructorBuilder.AddCode(call); } else { throw new InvalidOperationException( $"Serialized for property {operationDescriptor.Name}.{property.Name} " + $"could not be created. GraphQLTypeName was empty"); } }
protected void AddConstructorAssignedField( string typename, string fieldName, ClassBuilder classBuilder, ConstructorBuilder constructorBuilder, bool skipNullCheck = false) { AddConstructorAssignedField( TypeReferenceBuilder.New().SetName(typename), fieldName, classBuilder, constructorBuilder, skipNullCheck); }
public static TypeReferenceBuilder ToBuilder( this ITypeDescriptor typeReferenceDescriptor, string?nameOverride = null, TypeReferenceBuilder?builder = null, bool isNonNull = false) { var actualBuilder = builder ?? TypeReferenceBuilder.New(); switch (typeReferenceDescriptor) { case ListTypeDescriptor listTypeDescriptor: actualBuilder.SetIsNullable(!isNonNull); actualBuilder.SetListType(); ToBuilder( listTypeDescriptor.InnerType, nameOverride, actualBuilder); break; case NamedTypeDescriptor namedTypeDescriptor: actualBuilder.SetIsNullable(!isNonNull); if (namedTypeDescriptor.IsLeafType() && !namedTypeDescriptor.IsEnum) { actualBuilder.SetName( $"{namedTypeDescriptor.Namespace}." + (nameOverride ?? namedTypeDescriptor.Name)); } else { actualBuilder.SetName(nameOverride ?? namedTypeDescriptor.Name); } break; case NonNullTypeDescriptor nonNullTypeDescriptor: ToBuilder( nonNullTypeDescriptor.InnerType, nameOverride, actualBuilder, true); break; default: throw new ArgumentOutOfRangeException(nameof(typeReferenceDescriptor)); } return(actualBuilder); }
private void AddBuildMethod( InterfaceTypeDescriptor resultNamedType, ClassBuilder classBuilder) { var buildMethod = classBuilder .AddMethod() .SetAccessModifier(AccessModifier.Public) .SetName("Build") .SetReturnType( TypeReferenceBuilder .New() .SetName(TypeNames.IOperationResult) .AddGeneric(resultNamedType.RuntimeType.Name)); buildMethod .AddParameter(_response) .SetType(TypeNames.Response.WithGeneric(TypeNames.JsonDocument)); var concreteResultType = CreateResultInfoName(resultNamedType.ImplementedBy.First().RuntimeType.Name); buildMethod.AddCode( AssignmentBuilder .New() .SetLefthandSide( $"({resultNamedType.RuntimeType.Name} Result, {concreteResultType} " + "Info)? data") .SetRighthandSide("null")); buildMethod.AddCode( AssignmentBuilder .New() .SetLefthandSide( TypeNames.IReadOnlyList .WithGeneric(TypeNames.IClientError) .MakeNullable() + " errors") .SetRighthandSide("null")); buildMethod.AddEmptyLine(); buildMethod.AddCode( TryCatchBuilder .New() .AddTryCode( IfBuilder .New() .SetCondition( ConditionBuilder .New() .Set("response.Body != null")) .AddCode( IfBuilder .New() .SetCondition( ConditionBuilder .New() .Set("response.Body.RootElement.TryGetProperty(" + $"\"data\", out {TypeNames.JsonElement} " + "dataElement) && dataElement.ValueKind == " + $"{TypeNames.JsonValueKind}.Object")) .AddCode("data = BuildData(dataElement);")) .AddCode( IfBuilder .New() .SetCondition( ConditionBuilder .New() .Set( "response.Body.RootElement.TryGetProperty(" + $"\"errors\", out {TypeNames.JsonElement} " + "errorsElement)")) .AddCode($"errors = {TypeNames.ParseError}(errorsElement);"))) .AddCatchBlock( CatchBlockBuilder .New() .SetExceptionVariable("ex") .AddCode( AssignmentBuilder.New() .SetLefthandSide("errors") .SetRighthandSide( ArrayBuilder.New() .SetDetermineStatement(false) .SetType(TypeNames.IClientError) .AddAssigment( MethodCallBuilder .Inline() .SetNew() .SetMethodName(TypeNames.ClientError) .AddArgument("ex.Message") .AddArgument("exception: ex")))))); buildMethod.AddEmptyLine(); buildMethod.AddCode( MethodCallBuilder .New() .SetReturn() .SetNew() .SetMethodName(TypeNames.OperationResult) .AddGeneric(resultNamedType.RuntimeType.Name) .AddArgument("data?.Result") .AddArgument("data?.Info") .AddArgument(_resultDataFactory) .AddArgument("errors")); }
private void AddBuildMethod( InterfaceTypeDescriptor resultNamedType, ClassBuilder classBuilder) { var buildMethod = classBuilder .AddMethod() .SetAccessModifier(AccessModifier.Public) .SetName("Build") .SetReturnType( TypeReferenceBuilder .New() .SetName(TypeNames.IOperationResult) .AddGeneric(resultNamedType.RuntimeType.Name)); buildMethod .AddParameter(_response) .SetType(TypeNames.Response.WithGeneric(TypeNames.JsonDocument)); var concreteResultType = CreateResultInfoName(resultNamedType.ImplementedBy.First().RuntimeType.Name); // (IGetFooResult Result, GetFooResultInfo Info)? data = null; buildMethod.AddCode( AssignmentBuilder .New() .SetLefthandSide( $"({resultNamedType.RuntimeType.Name} Result, {concreteResultType} " + "Info)? data") .SetRighthandSide("null")); // IReadOnlyList<IClientError>? errors = null; buildMethod.AddCode( AssignmentBuilder .New() .SetLefthandSide( TypeNames.IReadOnlyList .WithGeneric(TypeNames.IClientError) .MakeNullable() + " errors") .SetRighthandSide("null")); buildMethod.AddEmptyLine(); buildMethod.AddEmptyLine(); buildMethod.AddCode( IfBuilder.New() .SetCondition("response.Exception is null") .AddCode(CreateBuildDataSerialization()) .AddElse(CreateDataError("response.Exception")) ); buildMethod.AddEmptyLine(); buildMethod.AddCode( MethodCallBuilder .New() .SetReturn() .SetNew() .SetMethodName(TypeNames.OperationResult) .AddGeneric(resultNamedType.RuntimeType.Name) .AddArgument("data?.Result") .AddArgument("data?.Info") .AddArgument(_resultDataFactory) .AddArgument("errors")); }
protected override void Generate( CodeWriter writer, ResultBuilderDescriptor resultBuilderDescriptor, out string fileName) { var processed = new HashSet <string>(); var resultTypeDescriptor = resultBuilderDescriptor.ResultNamedType; var(classBuilder, constructorBuilder) = CreateClassBuilder(); fileName = resultBuilderDescriptor.Name; classBuilder.SetName(fileName); constructorBuilder.SetTypeName(fileName); classBuilder.AddImplements( $"{TypeNames.IOperationResultBuilder}<{TypeNames.JsonDocument}," + $" {resultTypeDescriptor.Name}>"); AddConstructorAssignedField( TypeNames.IEntityStore, _entityStoreFieldName, classBuilder, constructorBuilder); AddConstructorAssignedField( TypeReferenceBuilder.New() .SetName(TypeNames.Func) .AddGeneric(TypeNames.JsonElement) .AddGeneric(TypeNames.EntityId), _extractIdFieldName, classBuilder, constructorBuilder); AddConstructorAssignedField( TypeReferenceBuilder.New() .SetName(TypeNames.IOperationResultDataFactory) .AddGeneric(resultTypeDescriptor.Name), _resultDataFactoryFieldName, classBuilder, constructorBuilder); constructorBuilder.AddParameter( ParameterBuilder.New() .SetName(_serializerResolverParamName) .SetType(TypeNames.ISerializerResolver)); IEnumerable <ValueParserDescriptor> neededSerializers = resultBuilderDescriptor .ValueParsers .ToLookup(x => x.RuntimeType) .Select(x => x.First()); foreach (ValueParserDescriptor valueParser in neededSerializers) { var parserFieldName = $"_{valueParser.RuntimeType.Split('.').Last().WithLowerFirstChar()}Parser"; classBuilder.AddField( FieldBuilder.New().SetName(parserFieldName).SetType( TypeReferenceBuilder.New() .SetName(TypeNames.ILeafValueParser) .AddGeneric(valueParser.SerializedType) .AddGeneric(valueParser.RuntimeType))); constructorBuilder.AddCode( AssignmentBuilder.New() .AssertNonNull(parserFieldName) .SetLefthandSide(parserFieldName) .SetRighthandSide( MethodCallBuilder.New() .SetPrefix(_serializerResolverParamName + ".") .SetDetermineStatement(false) .SetMethodName( $"GetLeafValueParser<{valueParser.SerializedType}, " + $"{valueParser.RuntimeType}>") .AddArgument($"\"{valueParser.GraphQLTypeName}\""))); } AddBuildMethod( resultTypeDescriptor, classBuilder); AddBuildDataMethod( resultTypeDescriptor, classBuilder); AddRequiredDeserializeMethods( resultBuilderDescriptor.ResultNamedType, classBuilder, processed); CodeFileBuilder.New() .SetNamespace(resultBuilderDescriptor.ResultNamedType.Namespace) .AddType(classBuilder) .Build(writer); }
protected override void Generate( CodeWriter writer, ResultBuilderDescriptor resultBuilderDescriptor, out string fileName) { var processed = new HashSet <string>(); var resultTypeDescriptor = resultBuilderDescriptor.ResultNamedType as InterfaceTypeDescriptor ?? throw new InvalidOperationException( "A result type can only be generated for complex types"); var(classBuilder, constructorBuilder) = CreateClassBuilder(); fileName = resultBuilderDescriptor.RuntimeType.Name; classBuilder.SetName(fileName); constructorBuilder.SetTypeName(fileName); classBuilder.AddImplements( $"{TypeNames.IOperationResultBuilder}<{TypeNames.JsonDocument}," + $" {resultTypeDescriptor.RuntimeType.Name}>"); AddConstructorAssignedField( TypeNames.IEntityStore, _entityStoreFieldName, classBuilder, constructorBuilder); AddConstructorAssignedField( TypeReferenceBuilder.New() .SetName(TypeNames.Func) .AddGeneric(TypeNames.JsonElement) .AddGeneric(TypeNames.EntityId), _extractIdFieldName, classBuilder, constructorBuilder); AddConstructorAssignedField( TypeReferenceBuilder.New() .SetName(TypeNames.IOperationResultDataFactory) .AddGeneric(resultTypeDescriptor.RuntimeType.Name), _resultDataFactoryFieldName, classBuilder, constructorBuilder); constructorBuilder.AddParameter( ParameterBuilder.New() .SetName(_serializerResolverParamName) .SetType(TypeNames.ISerializerResolver)); IEnumerable <ValueParserDescriptor> valueParsers = resultBuilderDescriptor .ValueParsers .GroupBy(t => t.Name) .Select(t => t.First()); foreach (ValueParserDescriptor valueParser in valueParsers) { var parserFieldName = $"{GetFieldName(valueParser.Name)}Parser"; classBuilder.AddField( FieldBuilder.New() .SetReadOnly() .SetName(parserFieldName) .SetType( TypeReferenceBuilder.New() .SetName(TypeNames.ILeafValueParser) .AddGeneric(valueParser.SerializedType.ToString()) .AddGeneric(valueParser.RuntimeType.ToString()))); constructorBuilder.AddCode( AssignmentBuilder.New() .SetAssertNonNull() .SetAssertException( TypeNames.ArgumentException + $"(\"No serializer for type `{valueParser.Name}` found.\")") .SetLefthandSide(parserFieldName) .SetRighthandSide( MethodCallBuilder.New() .SetPrefix(_serializerResolverParamName + ".") .SetDetermineStatement(false) .SetMethodName( $"GetLeafValueParser<{valueParser.SerializedType}, " + $"{valueParser.RuntimeType}>") .AddArgument($"\"{valueParser.Name}\""))); } AddBuildMethod( resultTypeDescriptor, classBuilder); AddBuildDataMethod( resultTypeDescriptor, classBuilder); AddRequiredDeserializeMethods( resultBuilderDescriptor.ResultNamedType, classBuilder, processed); CodeFileBuilder.New() .SetNamespace( resultBuilderDescriptor.ResultNamedType.RuntimeType.NamespaceWithoutGlobal) .AddType(classBuilder) .Build(writer); }