private void GenerateIfForEachImplementedBy( MethodBuilder method, ComplexTypeDescriptor complexTypeDescriptor, Func<ObjectTypeDescriptor, IfBuilder> generator) { if (!(complexTypeDescriptor is InterfaceTypeDescriptor interfaceTypeDescriptor) || !interfaceTypeDescriptor.ImplementedBy.Any()) { return; } IEnumerable<ObjectTypeDescriptor> dataTypes = interfaceTypeDescriptor.ImplementedBy.Where(x => x.IsData()); IfBuilder ifChain = generator(dataTypes.First()); foreach (ObjectTypeDescriptor objectTypeDescriptor in dataTypes.Skip(1)) { ifChain.AddIfElse(generator(objectTypeDescriptor).SkipIndents()); } ifChain.AddElse(ExceptionBuilder.New(TypeNames.NotSupportedException)); method.AddCode(ifChain); }
private void AddDataTypeDeserializerMethod( ClassBuilder classBuilder, MethodBuilder methodBuilder, ComplexTypeDescriptor complexTypeDescriptor, HashSet <string> processed) { if (complexTypeDescriptor is InterfaceTypeDescriptor interfaceTypeDescriptor) { AddInterfaceDataTypeDeserializerToMethod(methodBuilder, interfaceTypeDescriptor); } else { MethodCallBuilder returnStatement = MethodCallBuilder .New() .SetReturn() .SetNew() .SetMethodName(complexTypeDescriptor.Name); foreach (PropertyDescriptor property in complexTypeDescriptor.Properties) { returnStatement.AddArgument(BuildUpdateMethodCall(property)); } methodBuilder.AddCode(returnStatement); } AddRequiredDeserializeMethods(complexTypeDescriptor, classBuilder, processed); }
private void GenerateIfForEachImplementedBy( MethodBuilder method, ComplexTypeDescriptor complexTypeDescriptor, Func <ObjectTypeDescriptor, IfBuilder> generator) { if (!(complexTypeDescriptor is InterfaceTypeDescriptor interfaceTypeDescriptor) || !interfaceTypeDescriptor.ImplementedBy.Any()) { return; } var ifChain = generator(interfaceTypeDescriptor.ImplementedBy.First()); foreach (ObjectTypeDescriptor objectTypeDescriptor in interfaceTypeDescriptor.ImplementedBy.Skip(1)) { ifChain.AddIfElse( generator(objectTypeDescriptor) .SkipIndents()); } ifChain.AddElse( CodeInlineBuilder.New() .SetText($"throw new {TypeNames.NotSupportedException}();")); method.AddCode(ifChain); }
private void AddComplexDataHandler( CSharpSyntaxGeneratorSettings settings, ClassBuilder classBuilder, ConstructorBuilder constructorBuilder, MethodBuilder method, ComplexTypeDescriptor complexTypeDescriptor, HashSet <string> processed, bool isNonNullable) { if (complexTypeDescriptor.ParentRuntimeType is null) { throw new InvalidOperationException(); } method .AddParameter(_dataParameterName) .SetType(complexTypeDescriptor.ParentRuntimeType .ToString() .MakeNullable(!isNonNullable)) .SetName(_dataParameterName); if (settings.IsStoreEnabled()) { method .AddParameter(_snapshot) .SetType(TypeNames.IEntityStoreSnapshot); } if (!isNonNullable) { method.AddCode(EnsureProperNullability(_dataParameterName, isNonNullable)); } const string returnValue = nameof(returnValue); method.AddCode($"{complexTypeDescriptor.RuntimeType.Name}? {returnValue};"); method.AddEmptyLine(); GenerateIfForEachImplementedBy( method, complexTypeDescriptor, o => GenerateComplexDataInterfaceIfClause(settings, o, returnValue)); method.AddCode($"return {returnValue};"); AddRequiredMapMethods( settings, _dataParameterName, complexTypeDescriptor, classBuilder, constructorBuilder, processed); }
private void AddEntityHandler( ClassBuilder classBuilder, ConstructorBuilder constructorBuilder, MethodBuilder method, ComplexTypeDescriptor complexTypeDescriptor, HashSet <string> processed, bool isNonNullable) { method .AddParameter(_entityId) .SetType(TypeNames.EntityId.MakeNullable(!isNonNullable)); method .AddParameter(_snapshot) .SetType(TypeNames.IEntityStoreSnapshot); if (!isNonNullable) { method.AddCode(EnsureProperNullability(_entityId, isNonNullable)); } if (complexTypeDescriptor is InterfaceTypeDescriptor interfaceTypeDescriptor) { foreach (ObjectTypeDescriptor implementee in interfaceTypeDescriptor.ImplementedBy .Where(x => x.IsEntity())) { NameString dataMapperName = CreateEntityMapperName(implementee.RuntimeType.Name, implementee.Name); if (processed.Add(dataMapperName)) { var dataMapperType = TypeNames.IEntityMapper.WithGeneric( CreateEntityType( implementee.Name, implementee.RuntimeType.NamespaceWithoutGlobal) .ToString(), implementee.RuntimeType.Name); AddConstructorAssignedField( dataMapperType, GetFieldName(dataMapperName), GetParameterName(dataMapperName), classBuilder, constructorBuilder); } method.AddCode(GenerateEntityHandlerIfClause(implementee, isNonNullable)); } } method.AddCode(ExceptionBuilder.New(TypeNames.NotSupportedException)); }
public static bool ContainsEntity(this ITypeDescriptor typeDescriptor) { return(typeDescriptor switch { ListTypeDescriptor listTypeDescriptor => listTypeDescriptor.InnerType.ContainsEntity(), ComplexTypeDescriptor namedTypeDescriptor => namedTypeDescriptor.Properties .Any(prop => prop.Type.IsEntityType() || prop.Type.ContainsEntity()), NonNullTypeDescriptor nonNullTypeDescriptor => nonNullTypeDescriptor.InnerType.ContainsEntity(), _ => false });
/// <summary> /// Adds all required deserializers of the given type descriptors properties /// </summary> protected void AddRequiredMapMethods( CSharpSyntaxGeneratorSettings settings, string propAccess, ComplexTypeDescriptor typeDescriptor, ClassBuilder classBuilder, ConstructorBuilder constructorBuilder, HashSet <string> processed, bool stopAtEntityMappers = false) { if (typeDescriptor is InterfaceTypeDescriptor interfaceType) { foreach (var objectTypeDescriptor in interfaceType.ImplementedBy) { AddRequiredMapMethods( settings, propAccess, objectTypeDescriptor, classBuilder, constructorBuilder, processed); } } else { foreach (var property in typeDescriptor.Properties) { AddMapMethod( settings, propAccess, property.Type, classBuilder, constructorBuilder, processed); if (property.Type.NamedType() is ComplexTypeDescriptor ct && !ct.IsLeafType() && !stopAtEntityMappers) { AddRequiredMapMethods( settings, propAccess, ct, classBuilder, constructorBuilder, processed); } } } }
private MethodCallBuilder GetMappingCall( ComplexTypeDescriptor complexTypeDescriptor, string idName) { return(MethodCallBuilder.New() .SetMethodName( GetFieldName( CreateEntityMapperName( complexTypeDescriptor.RuntimeType.Name, complexTypeDescriptor.Name)) + ".Map") .SetDetermineStatement(false) .AddArgument( $"{StoreParamName}.GetEntity<" + $"{CreateEntityTypeName(complexTypeDescriptor.Name)}>" + $"({idName}) ?? throw new {TypeNames.ArgumentNullException}()")); }
private void AddEntityOrDataTypeDeserializerMethod( ClassBuilder classBuilder, MethodBuilder methodBuilder, ComplexTypeDescriptor complexTypeDescriptor, HashSet <string> processed) { if (complexTypeDescriptor is InterfaceTypeDescriptor interfaceTypeDescriptor) { AddEntityDataTypeDeserializerToMethod(methodBuilder, interfaceTypeDescriptor); } else { throw new InvalidOperationException(); } AddRequiredDeserializeMethods(complexTypeDescriptor, classBuilder, processed); }
private void AddComplexDataHandler( ClassBuilder classBuilder, ConstructorBuilder constructorBuilder, MethodBuilder method, ComplexTypeDescriptor complexTypeDescriptor, HashSet <string> processed, bool isNonNullable) { if (complexTypeDescriptor.ParentRuntimeType is null) { throw new InvalidOperationException(); } method.AddParameter( ParameterBuilder.New() .SetType(complexTypeDescriptor.ParentRuntimeType.ToString()) .SetName(_dataParameterName)); if (!isNonNullable) { method.AddCode( EnsureProperNullability( _dataParameterName, isNonNullable)); } var variableName = "returnValue"; method.AddCode($"{complexTypeDescriptor.RuntimeType.Name} {variableName} = default!;"); method.AddEmptyLine(); GenerateIfForEachImplementedBy( method, complexTypeDescriptor, o => GenerateComplexDataInterfaceIfClause(o, variableName)); method.AddCode($"return {variableName};"); AddRequiredMapMethods( _dataParameterName, complexTypeDescriptor, classBuilder, constructorBuilder, processed); }
private void AddDataHandler( ClassBuilder classBuilder, ConstructorBuilder constructorBuilder, MethodBuilder method, ComplexTypeDescriptor namedTypeDescriptor, HashSet <string> processed, bool isNonNullable) { method .AddParameter(_dataParameterName) .SetType(namedTypeDescriptor.ParentRuntimeType ! .ToString() .MakeNullable(!isNonNullable)); method .AddParameter(_snapshot) .SetType(TypeNames.IEntityStoreSnapshot); if (!isNonNullable) { method.AddCode(EnsureProperNullability(_dataParameterName, isNonNullable)); } const string returnValue = nameof(returnValue); method.AddCode($"{namedTypeDescriptor.RuntimeType.Name} {returnValue} = default!;"); method.AddEmptyLine(); GenerateIfForEachImplementedBy( method, namedTypeDescriptor, o => GenerateDataInterfaceIfClause(o, isNonNullable, returnValue)); method.AddCode($"return {returnValue};"); AddRequiredMapMethods( _dataParameterName, namedTypeDescriptor, classBuilder, constructorBuilder, processed); }
protected override void Generate( CodeWriter writer, ITypeDescriptor typeDescriptor, out string fileName) { ComplexTypeDescriptor complexTypeDescriptor = typeDescriptor as ComplexTypeDescriptor ?? throw new InvalidOperationException( "A result entity mapper can only be generated for complex types"); var(classBuilder, constructorBuilder) = CreateClassBuilder(); var className = CreateResultInfoName(complexTypeDescriptor.RuntimeType.Name); fileName = className; classBuilder .AddImplements(TypeNames.IOperationResultDataInfo) .SetName(fileName); constructorBuilder .SetTypeName(complexTypeDescriptor.RuntimeType.Name) .SetAccessModifier(AccessModifier.Public); foreach (var prop in complexTypeDescriptor.Properties) { var propTypeBuilder = prop.Type.ToEntityIdBuilder(); // Add Property to class classBuilder.AddProperty( prop.Name, x => x.SetType(propTypeBuilder).SetAccessModifier(AccessModifier.Public)); // Add initialization of property to the constructor var paramName = GetParameterName(prop.Name); ParameterBuilder parameterBuilder = ParameterBuilder.New() .SetName(paramName) .SetType(propTypeBuilder); constructorBuilder.AddParameter(parameterBuilder); constructorBuilder.AddCode(prop.Name + " = " + paramName + ";"); } classBuilder.AddProperty( "EntityIds", x => x.SetType(TypeNames.IReadOnlyCollection.WithGeneric(TypeNames.EntityId)) .AsLambda("_entityIds")); classBuilder.AddProperty("Version", x => x.SetType("ulong").AsLambda("_version")); AddConstructorAssignedField( $"{TypeNames.IReadOnlyCollection}<{TypeNames.EntityId}>", "_entityIds", classBuilder, constructorBuilder); AddConstructorAssignedField( "ulong", "_version", classBuilder, constructorBuilder, true); // WithVersion classBuilder.AddMethod( "WithVersion", x => x.SetAccessModifier(AccessModifier.Public) .SetReturnType(TypeNames.IOperationResultDataInfo) .AddParameter(ParameterBuilder.New() .SetType("ulong") .SetName("version")) .AddCode(MethodCallBuilder.New() .SetPrefix("return new ") .SetMethodName(className) .AddArgumentRange( complexTypeDescriptor.Properties.Select(x => x.Name.Value)) .AddArgument("_entityIds") .AddArgument("_version"))); CodeFileBuilder .New() .SetNamespace(complexTypeDescriptor.RuntimeType.NamespaceWithoutGlobal) .AddType(classBuilder) .Build(writer); }
private void AddDataTypeDeserializerMethod( ClassBuilder classBuilder, MethodBuilder methodBuilder, ComplexTypeDescriptor complexTypeDescriptor, HashSet <string> processed) { if (complexTypeDescriptor is InterfaceTypeDescriptor interfaceTypeDescriptor) { methodBuilder.AddCode( "var typename = obj.Value.GetProperty(\"__typename\").GetString();"); // If the type is an interface foreach (ObjectTypeDescriptor concreteType in interfaceTypeDescriptor.ImplementedBy) { methodBuilder.AddEmptyLine(); var ifStatement = IfBuilder.New() .SetCondition( $"typename?.Equals(\"{concreteType.Name}\", " + $"{TypeNames.OrdinalStringComparison}) ?? false"); var dataTypeName = $"{concreteType.RuntimeType.Namespace}.State." + CreateDataTypeName(concreteType.Name); var returnStatement = MethodCallBuilder.New() .SetPrefix("return new ") .SetMethodName(dataTypeName); returnStatement.AddArgument("typename"); foreach (PropertyDescriptor property in concreteType.Properties) { returnStatement.AddArgument( CodeBlockBuilder.New() .AddCode($"{GetParameterName(property.Name)}: ") .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(complexTypeDescriptor.Name); foreach (PropertyDescriptor property in complexTypeDescriptor.Properties) { returnStatement.AddArgument(BuildUpdateMethodCall(property)); } methodBuilder.AddCode(returnStatement); } AddRequiredDeserializeMethods( complexTypeDescriptor, classBuilder, processed); }
protected override void Generate(ITypeDescriptor typeDescriptor, CSharpSyntaxGeneratorSettings settings, CodeWriter writer, out string fileName, out string?path, out string ns) { ComplexTypeDescriptor complexTypeDescriptor = typeDescriptor as ComplexTypeDescriptor ?? throw new InvalidOperationException( "A result entity mapper can only be generated for complex types"); var className = CreateResultInfoName(complexTypeDescriptor.RuntimeType.Name); fileName = className; path = State; ns = CreateStateNamespace(complexTypeDescriptor.RuntimeType.NamespaceWithoutGlobal); ClassBuilder classBuilder = ClassBuilder .New() .AddImplements(TypeNames.IOperationResultDataInfo) .SetName(fileName); ConstructorBuilder constructorBuilder = classBuilder .AddConstructor() .SetTypeName(complexTypeDescriptor.RuntimeType.Name); foreach (var prop in complexTypeDescriptor.Properties) { TypeReferenceBuilder propTypeBuilder = prop.Type.ToStateTypeReference(); // Add Property to class classBuilder .AddProperty(prop.Name) .SetComment(prop.Description) .SetType(propTypeBuilder) .SetPublic(); // Add initialization of property to the constructor var paramName = GetParameterName(prop.Name); constructorBuilder.AddParameter(paramName).SetType(propTypeBuilder); constructorBuilder.AddCode( AssignmentBuilder .New() .SetLefthandSide(prop.Name) .SetRighthandSide(paramName)); } classBuilder .AddProperty("EntityIds") .SetType(TypeNames.IReadOnlyCollection.WithGeneric(TypeNames.EntityId)) .AsLambda(settings.IsStoreEnabled() ? CodeInlineBuilder.From(_entityIds) : MethodCallBuilder.Inline() .SetMethodName(TypeNames.Array, "Empty") .AddGeneric(TypeNames.EntityId)); classBuilder .AddProperty("Version") .SetType(TypeNames.UInt64) .AsLambda(settings.IsStoreEnabled() ? _version : "0"); if (settings.IsStoreEnabled()) { AddConstructorAssignedField( TypeNames.IReadOnlyCollection.WithGeneric(TypeNames.EntityId), _entityIds, entityIds, classBuilder, constructorBuilder); AddConstructorAssignedField( TypeNames.UInt64, _version, version, classBuilder, constructorBuilder, true); } // WithVersion classBuilder .AddMethod("WithVersion") .SetAccessModifier(AccessModifier.Public) .SetReturnType(TypeNames.IOperationResultDataInfo) .AddParameter(version, x => x.SetType(TypeNames.UInt64)) .AddCode(MethodCallBuilder .New() .SetReturn() .SetNew() .SetMethodName(className) .AddArgumentRange( complexTypeDescriptor.Properties.Select(x => x.Name.Value)) .If(settings.IsStoreEnabled(), x => x.AddArgument(_entityIds).AddArgument(version))); classBuilder.Build(writer); }
protected override void Generate(ITypeDescriptor typeDescriptor, CSharpSyntaxGeneratorSettings settings, CodeWriter writer, out string fileName, out string?path, out string ns) { ComplexTypeDescriptor descriptor = typeDescriptor as ComplexTypeDescriptor ?? throw new InvalidOperationException( "A result data factory can only be generated for complex types"); fileName = CreateResultFactoryName(descriptor.RuntimeType.Name); path = State; ns = CreateStateNamespace(descriptor.RuntimeType.NamespaceWithoutGlobal); ClassBuilder classBuilder = ClassBuilder .New() .SetName(fileName) .AddImplements( TypeNames.IOperationResultDataFactory.WithGeneric(descriptor.RuntimeType)); ConstructorBuilder constructorBuilder = classBuilder .AddConstructor() .SetTypeName(descriptor.Name); if (settings.IsStoreEnabled()) { AddConstructorAssignedField( TypeNames.IEntityStore, _entityStore, entityStore, classBuilder, constructorBuilder); } MethodCallBuilder returnStatement = MethodCallBuilder .New() .SetReturn() .SetNew() .SetMethodName(descriptor.RuntimeType.Name); foreach (PropertyDescriptor property in descriptor.Properties) { returnStatement .AddArgument(BuildMapMethodCall(settings, _info, property)); } IfBuilder ifHasCorrectType = IfBuilder .New() .SetCondition( $"{_dataInfo} is {CreateResultInfoName(descriptor.RuntimeType.Name)} {_info}") .AddCode(returnStatement); MethodBuilder createMethod = classBuilder .AddMethod("Create") .SetAccessModifier(AccessModifier.Public) .SetReturnType(descriptor.RuntimeType.Name) .AddParameter(_dataInfo, b => b.SetType(TypeNames.IOperationResultDataInfo)) .AddParameter( _snapshot, b => b.SetDefault("null") .SetType(TypeNames.IEntityStoreSnapshot.MakeNullable())); if (settings.IsStoreEnabled()) { createMethod .AddCode( IfBuilder.New() .SetCondition($"{_snapshot} is null") .AddCode( AssignmentBuilder .New() .SetLefthandSide(_snapshot) .SetRighthandSide($"{_entityStore}.CurrentSnapshot"))) .AddEmptyLine(); } createMethod.AddCode(ifHasCorrectType) .AddEmptyLine() .AddCode( ExceptionBuilder .New(TypeNames.ArgumentException) .AddArgument( $"\"{CreateResultInfoName(descriptor.RuntimeType.Name)} expected.\"")); var processed = new HashSet <string>(); AddRequiredMapMethods( settings, _info, descriptor, classBuilder, constructorBuilder, processed, true); classBuilder .AddProperty("ResultType") .SetType(TypeNames.Type) .AsLambda($"typeof({descriptor.RuntimeType.Namespace}.{descriptor.Implements[0]})") .SetInterface(TypeNames.IOperationResultDataFactory); classBuilder .AddMethod("Create") .SetInterface(TypeNames.IOperationResultDataFactory) .SetReturnType(TypeNames.Object) .AddParameter(_dataInfo, b => b.SetType(TypeNames.IOperationResultDataInfo)) .AddParameter( _snapshot, b => b.SetType(TypeNames.IEntityStoreSnapshot.MakeNullable())) .AddCode( MethodCallBuilder .New() .SetReturn() .SetMethodName("Create") .AddArgument(_dataInfo) .AddArgument(_snapshot)); classBuilder.Build(writer); }
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); }
protected override void Generate( CodeWriter writer, ITypeDescriptor typeDescriptor, out string fileName) { var(classBuilder, constructorBuilder) = CreateClassBuilder(false); ComplexTypeDescriptor descriptor = typeDescriptor as ComplexTypeDescriptor ?? throw new InvalidOperationException( "A result entity mapper can only be generated for complex types"); // Setup class fileName = descriptor.ExtractMapperName(); classBuilder .AddImplements( TypeNames.IEntityMapper .WithGeneric(descriptor.ExtractTypeName(), descriptor.RuntimeType.Name)) .SetName(fileName); constructorBuilder.SetTypeName(descriptor.Name); if (descriptor.ContainsEntity()) { AddConstructorAssignedField( TypeNames.IEntityStore, StoreFieldName, classBuilder, constructorBuilder); } // Define map method MethodBuilder mapMethod = MethodBuilder.New() .SetName(_mapMethodName) .SetAccessModifier(AccessModifier.Public) .SetReturnType(descriptor.RuntimeType.Name) .AddParameter( ParameterBuilder.New() .SetType( descriptor.Kind == TypeKind.EntityType ? CreateEntityTypeName(descriptor.Name) : descriptor.Name) .SetName(_entityParamName)); var constructorCall = MethodCallBuilder .New() .SetMethodName($"return new {descriptor.RuntimeType.Name}"); if (typeDescriptor is ComplexTypeDescriptor complexTypeDescriptor) { foreach (PropertyDescriptor property in complexTypeDescriptor.Properties) { constructorCall.AddArgument(BuildMapMethodCall(_entityParamName, property)); } } mapMethod.AddCode(constructorCall); if (constructorBuilder.HasParameters()) { classBuilder.AddConstructor(constructorBuilder); } classBuilder.AddMethod(mapMethod); AddRequiredMapMethods( _entityParamName, descriptor, classBuilder, constructorBuilder, new HashSet <string>()); CodeFileBuilder .New() .SetNamespace(descriptor.RuntimeType.NamespaceWithoutGlobal) .AddType(classBuilder) .Build(writer); }
protected override void Generate(ITypeDescriptor typeDescriptor, CSharpSyntaxGeneratorSettings settings, CodeWriter writer, out string fileName, out string?path, out string ns) { // Setup class ComplexTypeDescriptor descriptor = typeDescriptor as ComplexTypeDescriptor ?? throw new InvalidOperationException( "A result entity mapper can only be generated for complex types"); fileName = descriptor.ExtractMapperName(); path = State; ns = CreateStateNamespace(descriptor.RuntimeType.NamespaceWithoutGlobal); ClassBuilder classBuilder = ClassBuilder .New() .AddImplements( TypeNames.IEntityMapper .WithGeneric( descriptor.ExtractType().ToString(), descriptor.RuntimeType.Name)) .SetName(fileName); ConstructorBuilder constructorBuilder = ConstructorBuilder .New() .SetTypeName(descriptor.Name); AddConstructorAssignedField( TypeNames.IEntityStore, _entityStore, entityStore, 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.Entity ? CreateEntityType( descriptor.Name, descriptor.RuntimeType.NamespaceWithoutGlobal) .ToString() : descriptor.Name) .SetName(_entity)) .AddParameter( _snapshot, b => b.SetDefault("null") .SetType(TypeNames.IEntityStoreSnapshot.MakeNullable())); mapMethod .AddCode(IfBuilder .New() .SetCondition($"{_snapshot} is null") .AddCode(AssignmentBuilder .New() .SetLefthandSide(_snapshot) .SetRighthandSide($"{_entityStore}.CurrentSnapshot"))) .AddEmptyLine(); MethodCallBuilder constructorCall = MethodCallBuilder .New() .SetReturn() .SetNew() .SetMethodName(descriptor.RuntimeType.Name); if (typeDescriptor is ComplexTypeDescriptor complexTypeDescriptor) { foreach (PropertyDescriptor property in complexTypeDescriptor.Properties) { constructorCall.AddArgument(BuildMapMethodCall(settings, _entity, property)); } } mapMethod.AddCode(constructorCall); if (constructorBuilder.HasParameters()) { classBuilder.AddConstructor(constructorBuilder); } classBuilder.AddMethod(mapMethod); AddRequiredMapMethods( settings, _entity, descriptor, classBuilder, constructorBuilder, new HashSet <string>()); classBuilder.Build(writer); }
protected override void Generate( CodeWriter writer, ITypeDescriptor typeDescriptor, out string fileName) { ComplexTypeDescriptor complexTypeDescriptor = typeDescriptor as ComplexTypeDescriptor ?? throw new InvalidOperationException( "A result entity mapper can only be generated for complex types"); var className = CreateResultInfoName(complexTypeDescriptor.RuntimeType.Name); fileName = className; ClassBuilder classBuilder = ClassBuilder .New() .AddImplements(TypeNames.IOperationResultDataInfo) .SetName(fileName); ConstructorBuilder constructorBuilder = classBuilder .AddConstructor() .SetTypeName(complexTypeDescriptor.RuntimeType.Name); foreach (var prop in complexTypeDescriptor.Properties) { TypeReferenceBuilder propTypeBuilder = prop.Type.ToEntityIdBuilder(); // Add Property to class classBuilder .AddProperty(prop.Name) .SetType(propTypeBuilder) .SetPublic(); // Add initialization of property to the constructor var paramName = GetParameterName(prop.Name); constructorBuilder.AddParameter(paramName).SetType(propTypeBuilder); constructorBuilder.AddCode( AssignmentBuilder .New() .SetLefthandSide(prop.Name) .SetRighthandSide(paramName)); } classBuilder .AddProperty("EntityIds") .SetType(TypeNames.IReadOnlyCollection.WithGeneric(TypeNames.EntityId)) .AsLambda(_entityIds); classBuilder .AddProperty("Version") .SetType(TypeNames.UInt64) .AsLambda(_version); AddConstructorAssignedField( TypeNames.IReadOnlyCollection.WithGeneric(TypeNames.EntityId), _entityIds, classBuilder, constructorBuilder); AddConstructorAssignedField( TypeNames.UInt64, _version, classBuilder, constructorBuilder, true); // WithVersion const string version = nameof(version); classBuilder .AddMethod("WithVersion") .SetAccessModifier(AccessModifier.Public) .SetReturnType(TypeNames.IOperationResultDataInfo) .AddParameter(version, x => x.SetType(TypeNames.UInt64)) .AddCode(MethodCallBuilder .New() .SetReturn() .SetNew() .SetMethodName(className) .AddArgumentRange( complexTypeDescriptor.Properties.Select(x => x.Name.Value)) .AddArgument(_entityIds) .AddArgument(version)); CodeFileBuilder .New() .SetNamespace(complexTypeDescriptor.RuntimeType.NamespaceWithoutGlobal) .AddType(classBuilder) .Build(writer); }
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"); var(classBuilder, constructorBuilder) = CreateClassBuilder(); fileName = CreateResultFactoryName(descriptor.RuntimeType.Name); classBuilder .SetName(fileName) .AddImplements( // TODO: This should be descriptor.RuntimeType! $"{TypeNames.IOperationResultDataFactory}<{descriptor.RuntimeType.Name}>"); constructorBuilder .SetTypeName(descriptor.Name) .SetAccessModifier(AccessModifier.Public); AddConstructorAssignedField( TypeNames.IEntityStore, StoreParamName, classBuilder, constructorBuilder); var createMethod = MethodBuilder.New() .SetAccessModifier(AccessModifier.Public) .SetName("Create") .SetReturnType(descriptor.RuntimeType.Name) .AddParameter("dataInfo", b => b.SetType(TypeNames.IOperationResultDataInfo)); var returnStatement = MethodCallBuilder.New() .SetPrefix("return new ") .SetMethodName(descriptor.RuntimeType.Name); var ifHasCorrectType = IfBuilder.New() .SetCondition( $"dataInfo is {CreateResultInfoName(descriptor.RuntimeType.Name)} info"); foreach (PropertyDescriptor property in descriptor.Properties) { returnStatement.AddArgument( BuildMapMethodCall( "info", property)); } ifHasCorrectType.AddCode(returnStatement); createMethod.AddCode(ifHasCorrectType); createMethod.AddEmptyLine(); createMethod.AddCode( $"throw new {TypeNames.ArgumentException}(\"" + $"{CreateResultInfoName(descriptor.RuntimeType.Name)} expected.\");"); classBuilder.AddMethod(createMethod); var processed = new HashSet <string>(); AddRequiredMapMethods( "info", descriptor, classBuilder, constructorBuilder, processed, true); CodeFileBuilder .New() .SetNamespace(descriptor.RuntimeType.NamespaceWithoutGlobal) .AddType(classBuilder) .Build(writer); }
private void AddEntityOrUnionDataHandler( CSharpSyntaxGeneratorSettings settings, ClassBuilder classBuilder, ConstructorBuilder constructorBuilder, MethodBuilder method, ComplexTypeDescriptor complexTypeDescriptor, HashSet <string> processed, bool isNonNullable) { method .AddParameter(_dataParameterName) .SetType(TypeNames.EntityIdOrData.MakeNullable(!isNonNullable)) .SetName(_dataParameterName); method .AddParameter(_snapshot) .SetType(TypeNames.IEntityStoreSnapshot) .SetName(_snapshot); if (!isNonNullable) { method.AddCode(EnsureProperNullability(_dataParameterName, isNonNullable)); } var dataHandlerMethodName = MapMethodNameFromTypeName(complexTypeDescriptor) + "Entity"; MethodBuilder complexDataHandler = MethodBuilder .New() .SetReturnType( complexTypeDescriptor.RuntimeType.ToString().MakeNullable(!isNonNullable)) .SetName(dataHandlerMethodName); AddComplexDataHandler(settings, classBuilder, constructorBuilder, complexDataHandler, complexTypeDescriptor, processed, isNonNullable); classBuilder.AddMethod(complexDataHandler); var entityDataHandlerMethodName = MapMethodNameFromTypeName(complexTypeDescriptor) + "Data"; MethodBuilder entityDataHandler = MethodBuilder .New() .SetReturnType( complexTypeDescriptor.RuntimeType.ToString().MakeNullable(!isNonNullable)) .SetName(entityDataHandlerMethodName); AddEntityHandler( classBuilder, constructorBuilder, entityDataHandler, complexTypeDescriptor, processed, isNonNullable); classBuilder.AddMethod(entityDataHandler); method.AddEmptyLine(); var parameterName = isNonNullable ? _dataParameterName : $"{_dataParameterName}.Value"; IfBuilder ifBuilder = IfBuilder .New() .SetCondition($"{parameterName}.EntityId is {{ }} id") .AddCode(MethodCallBuilder .New() .SetReturn() .SetMethodName(entityDataHandlerMethodName) .AddArgument("id") .AddArgument(_snapshot)) .AddIfElse(IfBuilder .New() .SetCondition( $"{parameterName}.Data is {complexTypeDescriptor.ParentRuntimeType!} d") .AddCode(MethodCallBuilder .New() .SetReturn() .SetMethodName(dataHandlerMethodName) .AddArgument("d") .AddArgument(_snapshot))) .AddElse(ExceptionBuilder.New(TypeNames.ArgumentOutOfRangeException)); method.AddCode(ifBuilder); AddRequiredMapMethods( settings, _dataParameterName, complexTypeDescriptor, classBuilder, constructorBuilder, processed); }