public static ClassBuilder AddEquality( this ClassBuilder builder, string typeName, IReadOnlyList <PropertyDescriptor> properties) { const string obj = nameof(obj); const string other = nameof(other); builder.AddImplements(TypeNames.IEquatable.WithGeneric(typeName)); builder .AddMethod(nameof(IEquatable <object> .Equals)) .SetPublic() .SetOverride() .SetReturnType(TypeNames.Boolean) .AddParameter(obj, x => x.SetType(TypeNames.Object.MakeNullable())) .AddCode(CodeBlockBuilder .New() .AddCode(IfBuilder .New() .SetCondition(MethodCallBuilder .Inline() .SetMethodName(nameof(ReferenceEquals)) .AddArgument("null") .AddArgument(obj)) .AddCode("return false;")) .AddEmptyLine() .AddCode(IfBuilder .New() .SetCondition(MethodCallBuilder .Inline() .SetMethodName(nameof(ReferenceEquals)) .AddArgument("this") .AddArgument(obj)) .AddCode("return true;")) .AddEmptyLine() .AddCode(IfBuilder .New() .SetCondition($"{obj}.GetType() != GetType()") .AddCode("return false;")) .AddEmptyLine() .AddLine($"return Equals(({typeName}){obj});")); ConditionBuilder equalCondition = ConditionBuilder .New() .SetReturn() .SetDetermineStatement(); if (properties.Count == 0) { equalCondition.And("true"); } else { foreach (PropertyDescriptor property in properties) { equalCondition.And(ConditionBuilder .New() .Set(BuildPropertyComparison(property.Type, property.Name))); } } builder .AddMethod(nameof(IEquatable <object> .Equals)) .SetPublic() .SetReturnType(TypeNames.Boolean) .AddParameter(other, x => x.SetType(typeName.MakeNullable())) .AddCode(CodeBlockBuilder .New() .AddCode(IfBuilder .New() .SetCondition(MethodCallBuilder .Inline() .SetMethodName(nameof(ReferenceEquals)) .AddArgument("null") .AddArgument(other)) .AddCode("return false;")) .AddEmptyLine() .AddCode(IfBuilder .New() .SetCondition(MethodCallBuilder .Inline() .SetMethodName(nameof(ReferenceEquals)) .AddArgument("this") .AddArgument(other)) .AddCode("return true;")) .AddEmptyLine() .AddCode(IfBuilder .New() .SetCondition($"{other}.GetType() != GetType()") .AddCode("return false;")) .AddEmptyLine() .AddCode(equalCondition)); builder .AddMethod(nameof(GetHashCode)) .SetPublic() .SetOverride() .SetReturnType(TypeNames.Int32) .AddCode(HashCodeBuilder .New() .AddProperties(properties)); return(builder); }
private void AddDataTypeDeserializerMethod( ClassBuilder classBuilder, MethodBuilder methodBuilder, NamedTypeDescriptor namedTypeDescriptor, HashSet <string> processed) { if (namedTypeDescriptor.IsInterface) { methodBuilder.AddCode( "var typename = obj.Value.GetProperty(\"__typename\").GetString();"); // If the type is an interface foreach (NamedTypeDescriptor concreteType in namedTypeDescriptor.ImplementedBy) { methodBuilder.AddEmptyLine(); var ifStatement = IfBuilder.New() .SetCondition( $"typename?.Equals(\"{concreteType.GraphQLTypeName}\", " + $"{TypeNames.OrdinalStringComparisson}) ?? false"); var dataTypeName = $"global::{concreteType.Namespace}.State." + DataTypeNameFromTypeName(concreteType.GraphQLTypeName); var returnStatement = MethodCallBuilder.New() .SetPrefix("return new ") .SetMethodName(dataTypeName); returnStatement.AddArgument("typename"); foreach (PropertyDescriptor property in concreteType.Properties) { returnStatement.AddArgument( CodeBlockBuilder.New() .AddCode($"{property.Name.WithLowerFirstChar()}: ") .AddCode(BuildUpdateMethodCall(property))); } ifStatement.AddCode(returnStatement); methodBuilder.AddCode(ifStatement); } methodBuilder.AddEmptyLine(); methodBuilder.AddCode($"throw new {TypeNames.NotSupportedException}();"); } else { var returnStatement = MethodCallBuilder.New() .SetPrefix("return new ") .SetMethodName(namedTypeDescriptor.Name); foreach (PropertyDescriptor property in namedTypeDescriptor.Properties) { returnStatement.AddArgument(BuildUpdateMethodCall(property)); } methodBuilder.AddCode(returnStatement); } AddRequiredDeserializeMethods( namedTypeDescriptor, classBuilder, processed); }
protected override void Generate( CodeWriter writer, ITypeDescriptor typeDescriptor, out string fileName) { ComplexTypeDescriptor descriptor = typeDescriptor as ComplexTypeDescriptor ?? throw new InvalidOperationException( "A result data factory can only be generated for complex types"); fileName = CreateResultFactoryName(descriptor.RuntimeType.Name); ClassBuilder classBuilder = ClassBuilder .New() .SetName(fileName) .AddImplements( TypeNames.IOperationResultDataFactory .WithGeneric(descriptor.RuntimeType.Name)); ConstructorBuilder constructorBuilder = classBuilder .AddConstructor() .SetTypeName(descriptor.Name); AddConstructorAssignedField( TypeNames.IEntityStore, _entityStore, classBuilder, constructorBuilder); MethodCallBuilder returnStatement = MethodCallBuilder .New() .SetReturn() .SetNew() .SetMethodName(descriptor.RuntimeType.Name); foreach (PropertyDescriptor property in descriptor.Properties) { returnStatement .AddArgument(BuildMapMethodCall(_info, property)); } IfBuilder ifHasCorrectType = IfBuilder .New() .SetCondition( $"{_dataInfo} is {CreateResultInfoName(descriptor.RuntimeType.Name)} {_info}") .AddCode(returnStatement); classBuilder .AddMethod("Create") .SetAccessModifier(AccessModifier.Public) .SetReturnType(descriptor.RuntimeType.Name) .AddParameter(_dataInfo, b => b.SetType(TypeNames.IOperationResultDataInfo)) .AddCode(ifHasCorrectType) .AddEmptyLine() .AddCode( ExceptionBuilder .New(TypeNames.ArgumentException) .AddArgument( $"\"{CreateResultInfoName(descriptor.RuntimeType.Name)} expected.\"")); var processed = new HashSet <string>(); AddRequiredMapMethods( _info, descriptor, classBuilder, constructorBuilder, processed, true); CodeFileBuilder .New() .SetNamespace(descriptor.RuntimeType.NamespaceWithoutGlobal) .AddType(classBuilder) .Build(writer); }
private void AddBuildDataMethod( NamedTypeDescriptor resultNamedType, ClassBuilder classBuilder) { var objParameter = "obj"; var buildDataMethod = MethodBuilder.New() .SetAccessModifier(AccessModifier.Private) .SetName("BuildData") .SetReturnType( $"({resultNamedType.Name}, " + $"{ResultInfoNameFromTypeName(resultNamedType.ImplementedBy[0].Name)})") .AddParameter( ParameterBuilder.New() .SetType(TypeNames.JsonElement) .SetName(objParameter)); var sessionName = "session"; buildDataMethod.AddCode( CodeLineBuilder.New() .SetLine( CodeBlockBuilder.New() .AddCode( $"using {TypeNames.IEntityUpdateSession} {sessionName} = ") .AddCode(_entityStoreFieldName + ".BeginUpdate();"))); var entityIdsName = "entityIds"; buildDataMethod.AddCode( CodeLineBuilder.New() .SetLine( $"var {entityIdsName} = new {TypeNames.HashSet}<{TypeNames.EntityId}>();")); buildDataMethod.AddEmptyLine(); foreach (PropertyDescriptor property in resultNamedType.Properties.Where(prop => prop.Type.IsEntityType())) { buildDataMethod.AddCode( AssignmentBuilder.New() .SetLefthandSide(CodeBlockBuilder.New() .AddCode(property.Type.ToEntityIdBuilder()) .AddCode($"{property.Name.WithLowerFirstChar()}Id")) .SetRighthandSide(BuildUpdateMethodCall(property, ""))); } var resultInfoConstructor = MethodCallBuilder.New() .SetMethodName( $"new {ResultInfoNameFromTypeName(resultNamedType.ImplementedBy[0].Name)}") .SetDetermineStatement(false); foreach (PropertyDescriptor property in resultNamedType.Properties) { if (property.Type.IsEntityType()) { resultInfoConstructor.AddArgument($"{property.Name.WithLowerFirstChar()}Id"); } else { resultInfoConstructor.AddArgument(BuildUpdateMethodCall(property, "")); } } resultInfoConstructor.AddArgument(entityIdsName); resultInfoConstructor.AddArgument( $"{sessionName}.{TypeNames.IEntityUpdateSession_Version}"); buildDataMethod.AddEmptyLine(); var resultInfoName = "resultInfo"; buildDataMethod.AddCode( AssignmentBuilder.New() .SetLefthandSide($"var {resultInfoName}") .SetRighthandSide(resultInfoConstructor)); buildDataMethod.AddEmptyLine(); buildDataMethod.AddCode( $"return ({_resultDataFactoryFieldName}" + $".Create({resultInfoName}), {resultInfoName});"); classBuilder.AddMethod(buildDataMethod); }
private void AddUpdateEntityMethod( ClassBuilder classBuilder, MethodBuilder methodBuilder, INamedTypeDescriptor namedTypeDescriptor, HashSet <string> processed) { var entityIdVarName = "entityId"; methodBuilder.AddCode( AssignmentBuilder.New() .SetLefthandSide( CodeBlockBuilder.New() .AddCode(TypeNames.EntityId) .AddCode($" {entityIdVarName}")) .SetRighthandSide($"{_extractIdFieldName}({_objParamName}.Value)")); methodBuilder.AddCode($"{_entityIdsParam}.Add({entityIdVarName});"); methodBuilder.AddEmptyLine(); var entityVarName = "entity"; if (namedTypeDescriptor is InterfaceTypeDescriptor interfaceTypeDescriptor) { // If the type is an interface foreach (ObjectTypeDescriptor concreteType in interfaceTypeDescriptor.ImplementedBy) { methodBuilder.AddEmptyLine(); var ifStatement = IfBuilder.New() .SetCondition( $"entityId.Name.Equals(\"{concreteType.Name}\", " + $"{TypeNames.OrdinalStringComparison})"); var entityTypeName = CreateEntityTypeName(concreteType.Name); WriteEntityLoader( ifStatement, entityTypeName, entityVarName, entityIdVarName); WritePropertyAssignments( ifStatement, concreteType.Properties, entityVarName); ifStatement.AddEmptyLine(); ifStatement.AddCode($"return {entityIdVarName};"); methodBuilder.AddCode(ifStatement); } methodBuilder.AddEmptyLine(); methodBuilder.AddCode($"throw new {TypeNames.NotSupportedException}();"); } else if (namedTypeDescriptor is ComplexTypeDescriptor complexTypeDescriptor) { WriteEntityLoader( methodBuilder, CreateEntityTypeName(namedTypeDescriptor.Name), entityVarName, entityIdVarName); WritePropertyAssignments( methodBuilder, complexTypeDescriptor.Properties, entityVarName); methodBuilder.AddEmptyLine(); methodBuilder.AddCode($"return {entityIdVarName};"); } AddRequiredDeserializeMethods( namedTypeDescriptor, classBuilder, processed); }
protected override void Generate( CodeWriter writer, ITypeDescriptor typeDescriptor, out string fileName) { // Setup class ComplexTypeDescriptor descriptor = typeDescriptor as ComplexTypeDescriptor ?? throw new InvalidOperationException( "A result entity mapper can only be generated for complex types"); fileName = descriptor.ExtractMapperName(); ClassBuilder classBuilder = ClassBuilder .New() .AddImplements( TypeNames.IEntityMapper .WithGeneric(descriptor.ExtractTypeName(), descriptor.RuntimeType.Name)) .SetName(fileName); ConstructorBuilder constructorBuilder = ConstructorBuilder .New() .SetTypeName(descriptor.Name); if (descriptor.ContainsEntity()) { AddConstructorAssignedField( TypeNames.IEntityStore, StoreFieldName, classBuilder, constructorBuilder); } // Define map method MethodBuilder mapMethod = MethodBuilder .New() .SetName(_map) .SetAccessModifier(AccessModifier.Public) .SetReturnType(descriptor.RuntimeType.Name) .AddParameter( ParameterBuilder .New() .SetType( descriptor.Kind == TypeKind.EntityType ? CreateEntityTypeName(descriptor.Name) : descriptor.Name) .SetName(_entity)); MethodCallBuilder constructorCall = MethodCallBuilder .New() .SetReturn() .SetNew() .SetMethodName(descriptor.RuntimeType.Name); if (typeDescriptor is ComplexTypeDescriptor complexTypeDescriptor) { foreach (PropertyDescriptor property in complexTypeDescriptor.Properties) { constructorCall.AddArgument(BuildMapMethodCall(_entity, property)); } } mapMethod.AddCode(constructorCall); if (constructorBuilder.HasParameters()) { classBuilder.AddConstructor(constructorBuilder); } classBuilder.AddMethod(mapMethod); AddRequiredMapMethods( _entity, descriptor, classBuilder, constructorBuilder, new HashSet <string>()); CodeFileBuilder .New() .SetNamespace(descriptor.RuntimeType.NamespaceWithoutGlobal) .AddType(classBuilder) .Build(writer); }
protected override Task WriteAsync( CodeWriter writer, EnumValueSerializerDescriptor descriptor) { if (writer is null) { throw new ArgumentNullException(nameof(writer)); } if (descriptor is null) { throw new ArgumentNullException(nameof(descriptor)); } ClassBuilder classBuilder = ClassBuilder.New() .SetAccessModifier(AccessModifier.Public) .SetSealed() .SetName(descriptor.Name) .AddImplements(Types.IValueSerializer) .AddProperty(PropertyBuilder.New() .SetAccessModifier(AccessModifier.Public) .SetType("string") .SetName("Name") .SetGetter(CodeLineBuilder.New() .SetLine($"return \"{descriptor.EnumGraphQLTypeName}\";"))) .AddProperty(PropertyBuilder.New() .SetAccessModifier(AccessModifier.Public) .SetType(Types.ValueKind) .SetName("Kind") .SetGetter(CodeLineBuilder.New() .SetLine($"return {Types.ValueKind}.Enum;"))) .AddProperty(PropertyBuilder.New() .SetAccessModifier(AccessModifier.Public) .SetType(Types.Type) .SetName("ClrType") .SetGetter(CodeLineBuilder.New() .SetLine($"return typeof({descriptor.EnumTypeName});"))) .AddProperty(PropertyBuilder.New() .SetAccessModifier(AccessModifier.Public) .SetType(Types.Type) .SetName("SerializationType") .SetGetter(CodeLineBuilder.New() .SetLine($"return typeof(string);"))) .AddMethod(MethodBuilder.New() .SetAccessModifier(AccessModifier.Public) .SetReturnType("object?", NullableRefTypes) .SetReturnType("object", !NullableRefTypes) .SetName("Serialize") .AddParameter(ParameterBuilder.New() .SetType("object?", NullableRefTypes) .SetType("object", !NullableRefTypes) .SetName("value")) .AddCode(CreateSerializerMethodBody(descriptor, CodeWriter.Indent))) .AddMethod(MethodBuilder.New() .SetAccessModifier(AccessModifier.Public) .SetReturnType("object?", NullableRefTypes) .SetReturnType("object", !NullableRefTypes) .SetName("Deserialize") .AddParameter(ParameterBuilder.New() .SetType("object?", NullableRefTypes) .SetType("object", !NullableRefTypes) .SetName("serialized")) .AddCode(CreateDeserializerMethodBody(descriptor, CodeWriter.Indent))); return(CodeFileBuilder.New() .SetNamespace(descriptor.Namespace) .AddType(classBuilder) .BuildAsync(writer)); }