ef update wip

This commit is contained in:
CodeLiturgy 2022-08-27 20:56:19 +01:00
parent 340a89bbd2
commit c34da98ad8
5 changed files with 102 additions and 26 deletions

View File

@ -45,6 +45,7 @@
<ItemGroup> <ItemGroup>
<Folder Include="bin\Release\netstandard2.0" /> <Folder Include="bin\Release\netstandard2.0" />
<Folder Include="Sources\EntityFramework" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -46,11 +46,11 @@ namespace MapTo
protected ImmutableArray<string> Usings { get; private set; } protected ImmutableArray<string> Usings { get; private set; }
public static EfGeneratorContext Create(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, MemberDeclarationSyntax typeSyntax) public static EfGeneratorContext Create(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, CandidateMember candidateMember)
{ {
EfGeneratorContext context = typeSyntax switch EfGeneratorContext context = candidateMember.MemberDeclarationSyntax switch
{ {
PropertyDeclarationSyntax => new EfGeneratorContext(compilation, sourceGenerationOptions, typeSyntax), PropertyDeclarationSyntax => new EfGeneratorContext(compilation, sourceGenerationOptions, candidateMember.MemberDeclarationSyntax),
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()
}; };

View File

@ -10,15 +10,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace MapTo 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> /// <summary>
/// Ef methods source generator /// Ef methods source generator
/// </summary> /// </summary>
@ -34,12 +25,15 @@ namespace MapTo
/// <inheritdoc /> /// <inheritdoc />
public void Execute(GeneratorExecutionContext context) public void Execute(GeneratorExecutionContext context)
{ {
try try
{ {
var options = SourceGenerationOptions.From(context); var options = SourceGenerationOptions.From(context);
var compilation = context.Compilation var compilation = context.Compilation
.AddSource(ref context, EfAddMethodsAttributeSource.Generate(options)); .AddSource(ref context, EfAddMethodsAttributeSource.Generate(options))
.AddSource(ref context, EfUpdateMethodsAttributeSource.Generate(options));
if (context.SyntaxReceiver is EfMethodsSyntaxReceiver receiver && receiver.CandidateMembers.Any()) if (context.SyntaxReceiver is EfMethodsSyntaxReceiver receiver && receiver.CandidateMembers.Any())
{ {
@ -53,7 +47,7 @@ namespace MapTo
} }
} }
private static void AddGeneratedExtensions(GeneratorExecutionContext context, Compilation compilation, IEnumerable<MemberDeclarationSyntax> candidateTypes, SourceGenerationOptions options) private static void AddGeneratedExtensions(GeneratorExecutionContext context, Compilation compilation, IEnumerable<CandidateMember> candidateTypes, SourceGenerationOptions options)
{ {
//SpinWait.SpinUntil(() => Debugger.IsAttached); //SpinWait.SpinUntil(() => Debugger.IsAttached);
@ -68,7 +62,7 @@ namespace MapTo
} }
var (source, hintName) = memberDeclarationSyntax switch var (source, hintName) = memberDeclarationSyntax.MemberDeclarationSyntax switch
{ {
PropertyDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model), PropertyDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model),
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()

View File

@ -6,9 +6,22 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace MapTo namespace MapTo
{ {
internal enum EfMethodsAttributeType
{
Add,
Update,
Invalid
}
internal record CandidateMember(
MemberDeclarationSyntax MemberDeclarationSyntax,
EfMethodsAttributeType AttributeType
);
internal class EfMethodsSyntaxReceiver : ISyntaxReceiver internal class EfMethodsSyntaxReceiver : ISyntaxReceiver
{ {
public List<MemberDeclarationSyntax> CandidateMembers { get; } = new(); public List<CandidateMember> CandidateMembers { get; } = new();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode) public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{ {
@ -17,22 +30,44 @@ namespace MapTo
return; return;
} }
var syntaxAttributeState = EfMethodsAttributeType.Invalid;
var attributeSyntax = attributes var attributeSyntax = attributes
.SelectMany(a => a.Attributes) .SelectMany(a => a.Attributes)
.FirstOrDefault(a => a.Name is .FirstOrDefault(a =>
IdentifierNameSyntax { Identifier: { ValueText: EfAddMethodsAttributeSource.AttributeName } } // For: [EfAddMethods]
or
QualifiedNameSyntax // For: [MapTo.EfAddMethods]
{ {
Left: IdentifierNameSyntax { Identifier: { ValueText: Constants.RootNamespace } }, syntaxAttributeState = IsValidAttributeType(a);
Right: IdentifierNameSyntax { Identifier: { ValueText: EfAddMethodsAttributeSource.AttributeName } } return syntaxAttributeState != EfMethodsAttributeType.Invalid;
} });
);
if (attributeSyntax is not null) if (attributeSyntax is not null)
{ {
CandidateMembers.Add(typeDeclarationSyntax); CandidateMembers.Add(new CandidateMember(typeDeclarationSyntax, syntaxAttributeState));
} }
} }
private static EfMethodsAttributeType IsValidAttributeType(AttributeSyntax a)
{
return a.Name switch
{
IdentifierNameSyntax { Identifier: { ValueText: EfAddMethodsAttributeSource.AttributeName } } // For: [EfAddMethods]
or QualifiedNameSyntax // For: [MapTo.EfAddMethods]
{
Left: IdentifierNameSyntax { Identifier: { ValueText: Constants.RootNamespace } },
Right: IdentifierNameSyntax { Identifier: { ValueText: EfAddMethodsAttributeSource.AttributeName } }
} => EfMethodsAttributeType.Add,
IdentifierNameSyntax { Identifier: { ValueText: EfUpdateMethodsAttributeSource.AttributeName } } // For: [EfAddMethods]
or QualifiedNameSyntax // For: [MapTo.EfUpdateMethods]
{
Left: IdentifierNameSyntax { Identifier: { ValueText: Constants.RootNamespace } },
Right: IdentifierNameSyntax { Identifier: { ValueText: EfUpdateMethodsAttributeSource.AttributeName } }
} => EfMethodsAttributeType.Update,
_ => EfMethodsAttributeType.Invalid
};
}
} }
} }

View File

@ -0,0 +1,46 @@
using static MapTo.Sources.Constants;
namespace MapTo.Sources
{
public class EfUpdateMethodsAttributeSource
{
internal const string AttributeName = "EfUpdateMethods";
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 updateType = null, Type returnType = null, string keyPropertyMemberName, Type keyPropertyMemberType)")
.WriteOpeningBracket()
.WriteClosingBracket()
.WriteLine();
builder
.WriteClosingBracket() // class
.WriteClosingBracket(); // namespace
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
}
}
}