private void AddInterfaceDataTypeDeserializerToMethod( MethodBuilder methodBuilder, InterfaceTypeDescriptor interfaceTypeDescriptor) { methodBuilder.AddCode( AssignmentBuilder .New() .SetLefthandSide($"var {_typename}") .SetRighthandSide(MethodCallBuilder .Inline() .SetMethodName( _obj, "Value", nameof(JsonElement.GetProperty)) .AddArgument(WellKnownNames.TypeName.AsStringToken()) .Chain(x => x.SetMethodName(nameof(JsonElement.GetString))))); // If the type is an interface foreach (ObjectTypeDescriptor concreteType in interfaceTypeDescriptor.ImplementedBy) { MethodCallBuilder returnStatement = MethodCallBuilder .New() .SetReturn() .SetNew() .SetMethodName( $"{concreteType.RuntimeType.Namespace}.State." + CreateDataTypeName(concreteType.Name)) .AddArgument("typename"); foreach (PropertyDescriptor property in concreteType.Properties) { if (property.Name.Value.EqualsOrdinal(WellKnownNames.TypeName)) { continue; } returnStatement.AddArgument( CodeBlockBuilder .New() .AddCode($"{GetParameterName(property.Name)}: ") .AddCode(BuildUpdateMethodCall(property))); } IfBuilder ifStatement = IfBuilder .New() .SetCondition( $"typename?.Equals(\"{concreteType.Name}\", " + $"{TypeNames.OrdinalStringComparison}) ?? false") .AddCode(returnStatement); methodBuilder .AddEmptyLine() .AddCode(ifStatement); } methodBuilder .AddEmptyLine() .AddCode(ExceptionBuilder.New(TypeNames.NotSupportedException)); }
private void AddUpdateEntityMethod( ClassBuilder classBuilder, MethodBuilder methodBuilder, INamedTypeDescriptor namedTypeDescriptor, HashSet <string> processed) { methodBuilder.AddCode( AssignmentBuilder .New() .SetLefthandSide($"{TypeNames.EntityId} {_entityId}") .SetRighthandSide( MethodCallBuilder .Inline() .SetMethodName(_idSerializer, "Parse") .AddArgument($"{_obj}.Value"))); methodBuilder.AddCode( MethodCallBuilder .New() .SetMethodName(_entityIds, nameof(List <object> .Add)) .AddArgument(_entityId)); methodBuilder.AddEmptyLine(); if (namedTypeDescriptor is InterfaceTypeDescriptor interfaceTypeDescriptor) { // If the type is an interface foreach (ObjectTypeDescriptor concreteType in interfaceTypeDescriptor.ImplementedBy) { methodBuilder .AddEmptyLine() .AddCode(CreateUpdateEntityStatement(concreteType) .AddCode($"return {_entityId};")); } methodBuilder.AddEmptyLine(); methodBuilder.AddCode(ExceptionBuilder.New(TypeNames.NotSupportedException)); } else if (namedTypeDescriptor is ObjectTypeDescriptor objectTypeDescriptor) { BuildTryGetEntityIf( CreateEntityType( objectTypeDescriptor.Name, objectTypeDescriptor.RuntimeType.NamespaceWithoutGlobal)) .AddCode(CreateEntityConstructorCall(objectTypeDescriptor, false)) .AddElse(CreateEntityConstructorCall(objectTypeDescriptor, true)); methodBuilder.AddEmptyLine(); methodBuilder.AddCode($"return {_entityId};"); } AddRequiredDeserializeMethods(namedTypeDescriptor, classBuilder, processed); }
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 AddInterfaceDataTypeDeserializerToMethod( MethodBuilder methodBuilder, InterfaceTypeDescriptor interfaceTypeDescriptor) { methodBuilder.AddCode( AssignmentBuilder .New() .SetLefthandSide($"var {_typename}") .SetRighthandSide(MethodCallBuilder .Inline() .SetMethodName( _obj, "Value", nameof(JsonElement.GetProperty)) .AddArgument(WellKnownNames.TypeName.AsStringToken()) .Chain(x => x.SetMethodName(nameof(JsonElement.GetString))))); // If the type is an interface foreach (ObjectTypeDescriptor concreteType in interfaceTypeDescriptor.ImplementedBy) { MethodCallBuilder returnStatement = CreateBuildDataStatement(concreteType) .SetReturn(); IfBuilder ifStatement = IfBuilder .New() .SetCondition( $"typename?.Equals(\"{concreteType.Name}\", " + $"{TypeNames.OrdinalStringComparison}) ?? false") .AddCode(returnStatement); methodBuilder .AddEmptyLine() .AddCode(ifStatement); } methodBuilder .AddEmptyLine() .AddCode(ExceptionBuilder.New(TypeNames.NotSupportedException)); }
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); }
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)); }
protected virtual void AddFluentToMethod(MethodBuilder methodBuilder, ITable table) { var tableNamespace = TableNamespace(table); var tableClassName = TableClassName(table); var tableFullClassName = TableClassFullName(table); var tableClass = GenerationContext.FindClass(tableClassName, tableNamespace); var fluentExpression = MultiLineLambdaExpression.Create() .Parameter(p => p.Name("entity")) .RawLine($"entity.{ToTableFluent(table)}"); //.RawLine($"entity.ToTable(\"{table.Name}\", \"{table.Schema}\")"); var pks = table.Columns.Where(t => t.IsPrimaryKey); var hasCompositeKey = pks.Count() > 1; ; if (hasCompositeKey) { var def = string.Join(", ", pks.Select(pk => { var pkProp = tableClass.FindByMeta <PropertyBuilder>(pk); return($"t.{pkProp.GetName()}"); })); fluentExpression.RawLine($"entity.HasKey(t => new {{ {def} }})"); } else { var pk = pks.First(); var pkProp = tableClass.FindByMeta <PropertyBuilder>(pk); fluentExpression.RawLine($"entity.HasKey(t => t.{pkProp.GetName()})"); } table.Indexes.ForEach(i => { if (!ShouldGenerateIndex(i)) { return; } var line = RawLineBuilder.Create(); string rightExpr; if (i.Columns.Count == 1) { var indexProp = tableClass.FindByMeta <PropertyBuilder>(i.Columns.First()); rightExpr = $"t.{indexProp.GetName()}"; } else { var cols = string.Join(", ", i.Columns.Select(t => $"t.{tableClass.FindByMeta<PropertyBuilder>(t).GetName()}")); rightExpr = $"new {{ {cols} }}"; } line.Append($"entity.HasIndex(t => {rightExpr})"); line.Append($"\n\t.HasName(\"{i.Name}\")"); if (i.IsUnique) { line.Append("\n\t.IsUnique()"); } OnBeforeIndexLineAdded(line, i); fluentExpression.Add(line); }); table.Columns.ForEach(c => { var columnProp = tableClass.FindByMeta <PropertyBuilder>(c); var line = RawLineBuilder.Create(); line.Append($"entity.Property(t => t.{columnProp.GetName()})"); line.Append($".HasColumnType(\"{FluentColumnType(c)}\")"); if (c.IsPrimaryKey) { if (c.IsAutoIncrement) { line.Append(".ValueGeneratedOnAdd()"); } else { line.Append(".ValueGeneratedNever()"); } } else if (!string.IsNullOrWhiteSpace(c.DefaultValue)) { line.Append($".HasDefaultValueSql(\"{c.DefaultValue}\")"); } if (!c.IsNullable) { line.Append(".IsRequired()"); } if (c.CharacterMaximumLength.HasValue && c.CharacterMaximumLength != -1) { line.Append($".HasMaxLength({c.CharacterMaximumLength})"); } if (DataTypeResolver.IsString(c) && !DataTypeResolver.IsUnicode(c)) { line.Append(".IsUnicode(false)"); } fluentExpression.Add(line); }); table.ForeignKeys.ForEach(fk => { if (!TablesToGenerate.Contains(fk.PrimaryKeyColumn.Table)) { return; } var fkProp = tableClass.FindByMeta <PropertyBuilder>(fk); var fkColumnProp = tableClass.FindByMeta <PropertyBuilder>(fk.ForeignKeyColumn); var fkTableNamespace = TableNamespace(fk.PrimaryKeyColumn.Table); var fkTableClassName = TableClassName(fk.PrimaryKeyColumn.Table); var fkTableClass = GenerationContext.FindClass(fkTableClassName, fkTableNamespace); var reverseProp = fkTableClass.FindByMeta <PropertyBuilder>(fk); var line = RawLineBuilder.Create(); line.Append($"entity.HasOne(t => t.{fkProp.GetName()})"); if (!fk.IsOneToOne()) { line.Append($"\n\t.WithMany(t => t.{reverseProp.GetName()})"); line.Append($"\n\t.HasForeignKey(t => t.{fkColumnProp.GetName()})"); } else { line.Append($"\n\t.WithOne(t => t.{reverseProp.GetName()})"); line.Append($"\n\t.HasForeignKey<{tableFullClassName}>(t => t.{fkColumnProp.GetName()})"); } if (IsCascade(fk.DeleteCascadeAction)) { line.Append("\n\t.OnDelete(DeleteBehavior.Delete)"); } else if (IsSetNull(fk.DeleteCascadeAction)) { line.Append("\n\t.OnDelete(DeleteBehavior.SetNull)"); } else { line.Append("\n\t.OnDelete(DeleteBehavior.ClientSetNull)"); } line.Append($"\n\t.HasConstraintName(\"{fk.Name}\")"); line.Comment("Foreign Key"); fluentExpression.Add(line); }); var modelFluentLine = $"modelBuilder.Entity<{tableFullClassName}>({fluentExpression.GenerateInline()})"; methodBuilder.Add(RawLineBuilder.Create(modelFluentLine)); methodBuilder.AddEmptyLine(); }
private void AddArrayHandler( CSharpSyntaxGeneratorSettings settings, ClassBuilder classBuilder, ConstructorBuilder constructorBuilder, MethodBuilder methodBuilder, ListTypeDescriptor listTypeDescriptor, HashSet <string> processed, bool isNonNullable) { methodBuilder .AddParameter(_list) .SetType(listTypeDescriptor.ToStateTypeReference()); if (settings.IsStoreEnabled()) { methodBuilder .AddParameter(_snapshot) .SetType(TypeNames.IEntityStoreSnapshot); } var listVarName = GetParameterName(listTypeDescriptor.Name) + "s"; methodBuilder.AddCode(EnsureProperNullability(_list, isNonNullable)); methodBuilder.AddCode( AssignmentBuilder .New() .SetLefthandSide($"var {listVarName}") .SetRighthandSide( CodeBlockBuilder .New() .AddCode("new ") .AddCode(TypeNames.List) .AddCode("<") .AddCode( listTypeDescriptor.InnerType.ToTypeReference().SkipTrailingSpace()) .AddCode(">") .AddCode("()"))); methodBuilder.AddEmptyLine(); ForEachBuilder forEachBuilder = ForEachBuilder .New() .SetLoopHeader( CodeBlockBuilder .New() .AddCode(listTypeDescriptor.InnerType.ToStateTypeReference()) .AddCode($"{_child} in {_list}")) .AddCode( MethodCallBuilder .New() .SetMethodName(listVarName, nameof(List <object> .Add)) .AddArgument(MethodCallBuilder .Inline() .SetMethodName(MapMethodNameFromTypeName(listTypeDescriptor.InnerType)) .AddArgument(_child) .If(settings.IsStoreEnabled(), x => x.AddArgument(_snapshot)))); methodBuilder .AddCode(forEachBuilder) .AddEmptyLine() .AddCode($"return {listVarName};"); AddMapMethod( settings, listVarName, listTypeDescriptor.InnerType, classBuilder, constructorBuilder, processed); }
private void AddEntityDataTypeDeserializerToMethod( MethodBuilder methodBuilder, InterfaceTypeDescriptor interfaceTypeDescriptor) { methodBuilder.AddCode( AssignmentBuilder .New() .SetLefthandSide($"var {_typename}") .SetRighthandSide(MethodCallBuilder .Inline() .SetMethodName( _obj, "Value", nameof(JsonElement.GetProperty)) .AddArgument(WellKnownNames.TypeName.AsStringToken()) .Chain(x => x.SetMethodName(nameof(JsonElement.GetString))))); foreach (ObjectTypeDescriptor concreteType in interfaceTypeDescriptor.ImplementedBy) { ICode builder; if (concreteType.IsEntity()) { builder = CodeBlockBuilder .New() .AddCode( AssignmentBuilder .New() .SetLefthandSide($"{TypeNames.EntityId} {_entityId}") .SetRighthandSide( MethodCallBuilder .Inline() .SetMethodName(_idSerializer, "Parse") .AddArgument($"{_obj}.Value"))) .AddCode(CreateUpdateEntityStatement(concreteType) .AddCode(MethodCallBuilder .New() .SetReturn() .SetNew() .SetMethodName(TypeNames.EntityIdOrData) .AddArgument(_entityId))); } else { builder = MethodCallBuilder .New() .SetNew() .SetReturn() .SetMethodName(TypeNames.EntityIdOrData) .AddArgument(CreateBuildDataStatement(concreteType) .SetDetermineStatement(false) .SetNew()); } methodBuilder .AddEmptyLine() .AddCode(IfBuilder .New() .SetCondition( $"typename?.Equals(\"{concreteType.Name}\", " + $"{TypeNames.OrdinalStringComparison}) ?? false") .AddCode(builder)); } methodBuilder .AddEmptyLine() .AddCode(ExceptionBuilder.New(TypeNames.NotSupportedException)); }
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); }