Support Ef Add method
This commit is contained in:
parent
1400bd08e0
commit
340a89bbd2
|
@ -0,0 +1,249 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using MapTo.Extensions;
|
||||
using MapTo.Sources;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
#pragma warning disable CS8602
|
||||
|
||||
namespace MapTo
|
||||
{
|
||||
internal class EfGeneratorContext
|
||||
{
|
||||
private readonly List<SymbolDisplayPart> _ignoredNamespaces;
|
||||
|
||||
public EfGeneratorContext(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, MemberDeclarationSyntax memberSyntax)
|
||||
{
|
||||
Compilation = compilation;
|
||||
_ignoredNamespaces = new();
|
||||
Diagnostics = ImmutableArray<Diagnostic>.Empty;
|
||||
Usings = ImmutableArray.Create("System", Constants.RootNamespace);
|
||||
SourceGenerationOptions = sourceGenerationOptions;
|
||||
MemberSyntax = memberSyntax;
|
||||
|
||||
MappingContextTypeSymbol = compilation.GetTypeByMetadataNameOrThrow(MappingContextSource.FullyQualifiedName);
|
||||
|
||||
AddUsingIfRequired(sourceGenerationOptions.SupportNullableStaticAnalysis, "System.Diagnostics.CodeAnalysis");
|
||||
}
|
||||
|
||||
public ImmutableArray<Diagnostic> Diagnostics { get; private set; }
|
||||
|
||||
public EfMethodsModel? Model { get; private set; }
|
||||
|
||||
protected Compilation Compilation { get; }
|
||||
|
||||
protected INamedTypeSymbol MappingContextTypeSymbol { get; }
|
||||
|
||||
protected INamedTypeSymbol EfAddMethodsAttributeTypeSymbol { get; }
|
||||
|
||||
protected SourceGenerationOptions SourceGenerationOptions { get; }
|
||||
|
||||
protected MemberDeclarationSyntax MemberSyntax { get; }
|
||||
|
||||
protected ImmutableArray<string> Usings { get; private set; }
|
||||
|
||||
public static EfGeneratorContext Create(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, MemberDeclarationSyntax typeSyntax)
|
||||
{
|
||||
EfGeneratorContext context = typeSyntax switch
|
||||
{
|
||||
PropertyDeclarationSyntax => new EfGeneratorContext(compilation, sourceGenerationOptions, typeSyntax),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
context.Model = context.CreateMappingModel();
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
protected void AddDiagnostic(Diagnostic diagnostic)
|
||||
{
|
||||
Diagnostics = Diagnostics.Add(diagnostic);
|
||||
}
|
||||
|
||||
protected void AddUsingIfRequired(ISymbol? namedTypeSymbol) =>
|
||||
AddUsingIfRequired(namedTypeSymbol?.ContainingNamespace.IsGlobalNamespace == false, namedTypeSymbol?.ContainingNamespace);
|
||||
|
||||
protected void AddUsingIfRequired(bool condition, INamespaceSymbol? ns) =>
|
||||
AddUsingIfRequired(condition && ns is not null && !_ignoredNamespaces.Contains(ns.ToDisplayParts().First()), ns?.ToDisplayString());
|
||||
|
||||
protected void AddUsingIfRequired(bool condition, string? ns)
|
||||
{
|
||||
if (ns is not null && condition && ns != MemberSyntax.GetNamespace() && !Usings.Contains(ns))
|
||||
{
|
||||
Usings = Usings.Add(ns);
|
||||
}
|
||||
}
|
||||
|
||||
protected ImmutableArray<INamedTypeSymbol> GetEntityTypeSymbol(MemberDeclarationSyntax memberDeclarationSyntax, SemanticModel? semanticModel = null)
|
||||
{
|
||||
var attributeData = memberDeclarationSyntax.GetAttribute(EfAddMethodsAttributeSource.AttributeName);
|
||||
var sourceSymbol = GetEntityTypeSymbols(attributeData, semanticModel);
|
||||
return sourceSymbol;
|
||||
}
|
||||
|
||||
// we need two possible InamedTypeSymbol
|
||||
protected ImmutableArray<INamedTypeSymbol> GetEntityTypeSymbols(SyntaxNode? attributeSyntax, SemanticModel? semanticModel = null)
|
||||
{
|
||||
if (attributeSyntax is null)
|
||||
{
|
||||
return new ImmutableArray<INamedTypeSymbol>(){};
|
||||
}
|
||||
|
||||
semanticModel ??= Compilation.GetSemanticModel(attributeSyntax.SyntaxTree);
|
||||
var descendentNodes = attributeSyntax
|
||||
.DescendantNodes();
|
||||
|
||||
var sourceTypeExpressionSyntax = descendentNodes
|
||||
.OfType<TypeOfExpressionSyntax>()
|
||||
.ToImmutableArray();
|
||||
|
||||
// cast
|
||||
var resultList = new List<INamedTypeSymbol>();
|
||||
for (int i = 0; i < sourceTypeExpressionSyntax.Length; i++)
|
||||
{
|
||||
var sourceTypeExpression = sourceTypeExpressionSyntax[i];
|
||||
if (semanticModel.GetTypeInfo(sourceTypeExpression.Type).Type is INamedTypeSymbol namedTypeSymbol)
|
||||
{
|
||||
resultList.Add(namedTypeSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
return resultList.ToImmutableArray();
|
||||
}
|
||||
|
||||
|
||||
protected bool IsEnumerable(ISymbol property, out INamedTypeSymbol? namedTypeSymbolResult)
|
||||
{
|
||||
|
||||
if (!property.TryGetTypeSymbol(out var propertyType))
|
||||
{
|
||||
AddDiagnostic(DiagnosticsFactory.NoMatchingPropertyTypeFoundError(property));
|
||||
namedTypeSymbolResult = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
propertyType is INamedTypeSymbol namedTypeSymbol &&
|
||||
!propertyType.IsPrimitiveType() &&
|
||||
(Compilation.IsGenericEnumerable(propertyType) || propertyType.AllInterfaces.Any(i => Compilation.IsGenericEnumerable(i))))
|
||||
{
|
||||
namedTypeSymbolResult = namedTypeSymbol;
|
||||
return true;
|
||||
}
|
||||
namedTypeSymbolResult = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private EfMethodsModel? CreateMappingModel()
|
||||
{
|
||||
var semanticModel = Compilation.GetSemanticModel(MemberSyntax.SyntaxTree);
|
||||
/*if (semanticModel.GetDeclaredSymbol(MemberSyntax) is not INamedTypeSymbol typeSymbol)
|
||||
{
|
||||
AddDiagnostic(DiagnosticsFactory.TypeNotFoundError(MemberSyntax.GetLocation(), MemberSyntax.Identifier.ValueText));
|
||||
return null;
|
||||
}*/
|
||||
|
||||
var attributeTypeSymbols = GetEntityTypeSymbol(MemberSyntax, semanticModel);
|
||||
|
||||
// Main Entity
|
||||
var entityData = GetEntityTypeData(MemberSyntax, semanticModel);
|
||||
|
||||
string entityTypeName = entityData.Name, createTypeIdentifierName = entityData.Name, readTypeIdentifierName = entityData.Name;
|
||||
|
||||
string entityTypeFullName = entityData.ToDisplayString(), createTypeFullName = entityData.ToDisplayString(), readTypeFullName = entityData.ToDisplayString();
|
||||
|
||||
|
||||
if (attributeTypeSymbols.Length > 0)
|
||||
{
|
||||
// Create DTO
|
||||
createTypeIdentifierName = attributeTypeSymbols[0].Name;
|
||||
createTypeFullName = attributeTypeSymbols[0].ToDisplayString();
|
||||
}
|
||||
if (attributeTypeSymbols.Length > 1)
|
||||
{
|
||||
// Read DTO
|
||||
readTypeIdentifierName = attributeTypeSymbols[1].Name;
|
||||
readTypeFullName = attributeTypeSymbols[1].ToDisplayString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// get containing class type information
|
||||
ClassDeclarationSyntax classDeclarationSyntax = MemberSyntax.Parent as ClassDeclarationSyntax;
|
||||
|
||||
// context name
|
||||
var dbContextName = classDeclarationSyntax.Identifier.ValueText;
|
||||
var namespaceDeclaration = classDeclarationSyntax.Parent as NamespaceDeclarationSyntax;
|
||||
var namespaceFullName = namespaceDeclaration.Name.ToString();
|
||||
|
||||
var contextTypeFullName = $"{namespaceFullName}.{dbContextName}";
|
||||
|
||||
var propertyName = entityTypeName;
|
||||
|
||||
if (MemberSyntax is PropertyDeclarationSyntax propertyDeclarationSyntax)
|
||||
{
|
||||
propertyName = propertyDeclarationSyntax.Identifier.ValueText;
|
||||
}
|
||||
if (MemberSyntax is FieldDeclarationSyntax fieldDeclaration)
|
||||
{
|
||||
// TODO: Test
|
||||
propertyName = fieldDeclaration.ToString();
|
||||
}
|
||||
|
||||
|
||||
if (attributeTypeSymbols.IsDefaultOrEmpty)
|
||||
{
|
||||
AddDiagnostic(DiagnosticsFactory.MapFromAttributeNotFoundError(MemberSyntax.GetLocation()));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//var typeIdentifierName = MemberSyntax.GetIdentifierName();
|
||||
//var isTypeInheritFromMappedBaseClass = IsTypeInheritFromMappedBaseClass(semanticModel);
|
||||
|
||||
|
||||
return new EfMethodsModel(
|
||||
SourceGenerationOptions,
|
||||
namespaceFullName,
|
||||
propertyName,
|
||||
dbContextName,
|
||||
contextTypeFullName,
|
||||
entityTypeFullName,
|
||||
entityTypeName,
|
||||
createTypeFullName,
|
||||
createTypeIdentifierName,
|
||||
readTypeFullName,
|
||||
readTypeIdentifierName,
|
||||
Usings);
|
||||
}
|
||||
|
||||
private static ITypeSymbol GetEntityTypeData(MemberDeclarationSyntax memberDeclarationSyntax, SemanticModel? semanticModel = null)
|
||||
{
|
||||
var member = (memberDeclarationSyntax as PropertyDeclarationSyntax).Type;
|
||||
var genericSyntax = member as GenericNameSyntax;
|
||||
var typeInfo = semanticModel.GetTypeInfo(genericSyntax);
|
||||
var firstTypeArgument = (typeInfo.ConvertedType as INamedTypeSymbol).TypeArguments[0];
|
||||
return firstTypeArgument;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private string? ToQualifiedDisplayName(ISymbol? symbol)
|
||||
{
|
||||
if (symbol is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var containingNamespace = MemberSyntax.GetNamespace();
|
||||
var symbolNamespace = symbol.ContainingNamespace.ToDisplayString();
|
||||
return containingNamespace != symbolNamespace && _ignoredNamespaces.Contains(symbol.ContainingNamespace.ToDisplayParts().First())
|
||||
? symbol.ToDisplayString()
|
||||
: symbol.Name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using MapTo.Extensions;
|
||||
using MapTo.Sources;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace MapTo
|
||||
{
|
||||
/*/// <summary>
|
||||
/// Base source code generator typed class.
|
||||
/// </summary>
|
||||
public class SourceCodeGenerator : ISourceGenerator
|
||||
{
|
||||
public virtual void Initialize(GeneratorInitializationContext context) {}
|
||||
public virtual void Execute(GeneratorExecutionContext context) {}
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Ef methods source generator
|
||||
/// </summary>
|
||||
[Generator]
|
||||
public class EfMethodsGenerator: ISourceGenerator
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterForSyntaxNotifications(() => new EfMethodsSyntaxReceiver());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
var options = SourceGenerationOptions.From(context);
|
||||
|
||||
var compilation = context.Compilation
|
||||
.AddSource(ref context, EfAddMethodsAttributeSource.Generate(options));
|
||||
|
||||
if (context.SyntaxReceiver is EfMethodsSyntaxReceiver receiver && receiver.CandidateMembers.Any())
|
||||
{
|
||||
AddGeneratedExtensions(context, compilation, receiver.CandidateMembers, options);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddGeneratedExtensions(GeneratorExecutionContext context, Compilation compilation, IEnumerable<MemberDeclarationSyntax> candidateTypes, SourceGenerationOptions options)
|
||||
{
|
||||
//SpinWait.SpinUntil(() => Debugger.IsAttached);
|
||||
|
||||
foreach (var memberDeclarationSyntax in candidateTypes)
|
||||
{
|
||||
var mappingContext = EfGeneratorContext.Create(compilation, options, memberDeclarationSyntax);
|
||||
mappingContext.Diagnostics.ForEach(context.ReportDiagnostic);
|
||||
|
||||
if (mappingContext.Model is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
var (source, hintName) = memberDeclarationSyntax switch
|
||||
{
|
||||
PropertyDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
context.AddSource(hintName, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MapTo.Sources;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace MapTo
|
||||
{
|
||||
internal class EfMethodsSyntaxReceiver : ISyntaxReceiver
|
||||
{
|
||||
public List<MemberDeclarationSyntax> CandidateMembers { get; } = new();
|
||||
|
||||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
{
|
||||
if (syntaxNode is not MemberDeclarationSyntax { AttributeLists: { Count: >= 1 } attributes } typeDeclarationSyntax)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var attributeSyntax = attributes
|
||||
.SelectMany(a => a.Attributes)
|
||||
.FirstOrDefault(a => a.Name is
|
||||
IdentifierNameSyntax { Identifier: { ValueText: EfAddMethodsAttributeSource.AttributeName } } // For: [EfAddMethods]
|
||||
or
|
||||
QualifiedNameSyntax // For: [MapTo.EfAddMethods]
|
||||
{
|
||||
Left: IdentifierNameSyntax { Identifier: { ValueText: Constants.RootNamespace } },
|
||||
Right: IdentifierNameSyntax { Identifier: { ValueText: EfAddMethodsAttributeSource.AttributeName } }
|
||||
}
|
||||
);
|
||||
|
||||
if (attributeSyntax is not null)
|
||||
{
|
||||
CandidateMembers.Add(typeDeclarationSyntax);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using MapTo.Sources;
|
||||
|
||||
namespace MapTo.Extensions
|
||||
{
|
||||
internal static class EfGeneratorExtensions
|
||||
{
|
||||
internal static SourceCode GenerateEfMethods(this EfMethodsModel model)
|
||||
{
|
||||
var builder = new SourceBuilder();
|
||||
|
||||
return new SourceCode(builder.ToString(), $"{model.Namespace}.{model.EntityTypeIdentifierName}.g.cs");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ namespace MapTo.Extensions
|
|||
|
||||
public static string GetIdentifierName(this TypeDeclarationSyntax typeSyntax) => typeSyntax.Identifier.Text;
|
||||
|
||||
public static AttributeSyntax? GetAttribute(this TypeDeclarationSyntax typeDeclarationSyntax, string attributeName)
|
||||
public static AttributeSyntax? GetAttribute(this MemberDeclarationSyntax typeDeclarationSyntax, string attributeName)
|
||||
{
|
||||
var attributeLists = typeDeclarationSyntax.AttributeLists;
|
||||
var selection = attributeLists
|
||||
|
@ -51,7 +51,7 @@ namespace MapTo.Extensions
|
|||
public static AttributeData? GetAttribute(this ISymbol symbol, ITypeSymbol attributeSymbol) =>
|
||||
symbol.GetAttributes(attributeSymbol).FirstOrDefault();
|
||||
|
||||
public static string? GetNamespace(this TypeDeclarationSyntax typeDeclarationSyntax) => typeDeclarationSyntax
|
||||
public static string? GetNamespace(this MemberDeclarationSyntax typeDeclarationSyntax) => typeDeclarationSyntax
|
||||
.Ancestors()
|
||||
.OfType<NamespaceDeclarationSyntax>()
|
||||
.FirstOrDefault()
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using MapTo.Extensions;
|
||||
using MapTo.Sources;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
@ -17,7 +19,9 @@ namespace MapTo
|
|||
/// <inheritdoc />
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
|
||||
context.RegisterForSyntaxNotifications(() => new MapToSyntaxReceiver());
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -61,6 +65,7 @@ namespace MapTo
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
var (source, hintName) = typeDeclarationSyntax switch
|
||||
{
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using MapTo.Extensions;
|
||||
using MapTo.Sources;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
@ -71,7 +73,6 @@ namespace MapTo
|
|||
|
||||
public static MappingContext Create(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, TypeDeclarationSyntax typeSyntax)
|
||||
{
|
||||
//SpinWait.SpinUntil(() => Debugger.IsAttached);
|
||||
|
||||
MappingContext context = typeSyntax switch
|
||||
{
|
||||
|
|
|
@ -68,6 +68,26 @@ namespace MapTo
|
|||
ImmutableArray<string> Usings
|
||||
);
|
||||
|
||||
|
||||
internal record EfMethodsModel(
|
||||
SourceGenerationOptions Options,
|
||||
string Namespace,
|
||||
string PropertyName,
|
||||
string ContextTypeName,
|
||||
string ContestFullType,
|
||||
|
||||
string EntityTypeFullName,
|
||||
string EntityTypeIdentifierName,
|
||||
|
||||
string CreateTypeFullName,
|
||||
string CreateTypeIdentifierName,
|
||||
|
||||
string ReadTypeFullName,
|
||||
string ReadTypeIdentifierName,
|
||||
|
||||
ImmutableArray<string> Usings
|
||||
);
|
||||
|
||||
internal record SourceGenerationOptions(
|
||||
AccessModifier ConstructorAccessModifier,
|
||||
AccessModifier GeneratedMethodsAccessModifier,
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
using static MapTo.Sources.Constants;
|
||||
|
||||
|
||||
namespace MapTo.Sources
|
||||
{
|
||||
internal static class EfAddMethodsAttributeSource
|
||||
{
|
||||
internal const string AttributeName = "EfAddMethods";
|
||||
internal const string AttributeClassName = AttributeName + "Attribute";
|
||||
internal const string FullyQualifiedName = RootNamespace + "." + AttributeClassName;
|
||||
|
||||
internal static SourceCode Generate(SourceGenerationOptions options)
|
||||
{
|
||||
using var builder = new SourceBuilder()
|
||||
.WriteLine(GeneratedFilesHeader)
|
||||
.WriteLine("using System;")
|
||||
.WriteLine()
|
||||
.WriteLine($"namespace {RootNamespace}")
|
||||
.WriteOpeningBracket();
|
||||
|
||||
if (options.GenerateXmlDocument)
|
||||
{
|
||||
builder
|
||||
.WriteLine("/// <summary>")
|
||||
.WriteLine("/// Generate Add methods for interacting with the entity")
|
||||
.WriteLine("/// </summary>");
|
||||
}
|
||||
|
||||
builder
|
||||
.WriteLine("[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]")
|
||||
.WriteLine($"public sealed class {AttributeName}Attribute : Attribute")
|
||||
.WriteOpeningBracket();
|
||||
|
||||
builder
|
||||
.WriteLine($"public {AttributeName}Attribute(Type createDto = null, Type returnType = null)")
|
||||
.WriteOpeningBracket()
|
||||
.WriteClosingBracket()
|
||||
.WriteLine();
|
||||
|
||||
builder
|
||||
.WriteClosingBracket() // class
|
||||
.WriteClosingBracket(); // namespace
|
||||
|
||||
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
using System.Collections.Generic;
|
||||
using MapTo.Extensions;
|
||||
using static MapTo.Sources.Constants;
|
||||
|
||||
namespace MapTo.Sources
|
||||
{
|
||||
internal static class EfMethodsSource
|
||||
{
|
||||
internal static SourceCode Generate(EfMethodsModel model)
|
||||
{
|
||||
const bool writeDebugInfo = false;
|
||||
|
||||
List<string> constructorHeaders = new List<string>();
|
||||
|
||||
using var builder = new SourceBuilder()
|
||||
.WriteLine(GeneratedFilesHeader)
|
||||
.WriteUsings(model.Usings)
|
||||
.WriteLine("using Microsoft.EntityFrameworkCore;")
|
||||
.WriteLine()
|
||||
// Namespace declaration
|
||||
.WriteLine($"namespace {model.Namespace}")
|
||||
.WriteOpeningBracket()
|
||||
// Class declaration
|
||||
.WriteLine($"public static partial class {model.EntityTypeIdentifierName}Extensions")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine()
|
||||
.WriteLine($"public static (bool, {model.ReadTypeFullName}) Add{model.EntityTypeIdentifierName}(")
|
||||
.WriteLine($"this {model.ContestFullType} dbContext,")
|
||||
.WriteLine($"{model.CreateTypeFullName} {model.EntityTypeIdentifierName.ToLower()}toCreate)")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine($"var new{model.EntityTypeIdentifierName} = new {model.EntityTypeFullName}({model.EntityTypeIdentifierName.ToLower()}toCreate);")
|
||||
.WriteLine($"dbContext.{model.PropertyName}.Add(new{model.EntityTypeIdentifierName});")
|
||||
.WriteLine($"var success = dbContext.SaveChanges() >= 0;")
|
||||
.WriteLine($"return (success, new {model.ReadTypeFullName}(new{model.EntityTypeIdentifierName}));")
|
||||
.WriteClosingBracket();
|
||||
builder
|
||||
.WriteLine()
|
||||
// End class declaration
|
||||
.WriteClosingBracket()
|
||||
.WriteLine()
|
||||
// End namespace declaration
|
||||
.WriteClosingBracket();
|
||||
|
||||
return new(builder.ToString(), $"{model.Namespace}.{model.EntityTypeIdentifierName}Extensions.g.cs");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using MapTo.Tests.Extensions;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
|
@ -46,9 +48,9 @@ namespace MapTo.Tests.Infrastructure
|
|||
// NB: fail tests when the injected program isn't valid _before_ running generators
|
||||
compilation.GetDiagnostics().ShouldBeSuccessful();
|
||||
}
|
||||
|
||||
|
||||
var driver = CSharpGeneratorDriver.Create(
|
||||
new[] { new MapToGenerator() },
|
||||
new List<ISourceGenerator>() { new MapToGenerator(), new EfMethodsGenerator() },
|
||||
optionsProvider: new TestAnalyzerConfigOptionsProvider(analyzerConfigOptions),
|
||||
parseOptions: new CSharpParseOptions(languageVersion)
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue