Remove EfGenerator, migrated to separate project
This commit is contained in:
parent
b8637c94ab
commit
4e80156708
|
@ -1,41 +0,0 @@
|
|||
using static MapTo.Sources.Constants;
|
||||
|
||||
namespace MapTo.Sources
|
||||
{
|
||||
public class EfGeneratorAttributeSource
|
||||
{
|
||||
internal const string AttributeName = "EfGenerator";
|
||||
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.Class)]")
|
||||
.WriteLine($"public sealed class {AttributeName}Attribute : Attribute")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine();
|
||||
|
||||
builder
|
||||
.WriteClosingBracket() // class
|
||||
.WriteClosingBracket(); // namespace
|
||||
|
||||
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using static MapTo.Sources.Constants;
|
||||
|
||||
namespace MapTo.Sources
|
||||
{
|
||||
internal static class EfGetManyAttributeSource
|
||||
{
|
||||
internal const string AttributeName = "EfGetMany";
|
||||
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("/// Attribute for generating a function to get one EF entity with a predicate as argument and a return type for the projection.")
|
||||
.WriteLine("/// </summary>");
|
||||
}
|
||||
|
||||
builder
|
||||
.WriteLine("[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]")
|
||||
.WriteLine($"public sealed class {AttributeName}Attribute : Attribute")
|
||||
.WriteOpeningBracket();
|
||||
|
||||
builder
|
||||
.WriteLine($"public {AttributeName}Attribute(Type returnType){"{}"}")
|
||||
.WriteLine();
|
||||
|
||||
builder
|
||||
.WriteClosingBracket() // class
|
||||
.WriteClosingBracket(); // namespace
|
||||
|
||||
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using static MapTo.Sources.Constants;
|
||||
|
||||
namespace MapTo.Sources
|
||||
{
|
||||
internal class EfGetOneByAttributeSource
|
||||
{
|
||||
internal const string AttributeName = "EfGetOneBy";
|
||||
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(string bynameof, Type returnType)")
|
||||
.WriteOpeningBracket()
|
||||
.WriteClosingBracket()
|
||||
.WriteLine();
|
||||
|
||||
builder
|
||||
.WriteClosingBracket() // class
|
||||
.WriteClosingBracket(); // namespace
|
||||
|
||||
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
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, Type returnType, string keyPropertyMemberName)")
|
||||
.WriteOpeningBracket()
|
||||
.WriteClosingBracket()
|
||||
.WriteLine();
|
||||
|
||||
builder
|
||||
.WriteClosingBracket() // class
|
||||
.WriteClosingBracket(); // namespace
|
||||
|
||||
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using static MapTo.Sources.Constants;
|
||||
|
||||
namespace MapTo.Sources
|
||||
{
|
||||
internal static class EfGetOneAttributeSource
|
||||
{
|
||||
internal const string AttributeName = "EfGetOne";
|
||||
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("/// Attribute for generating a function to get one EF entity with a predicate as argument and a return type for the projection.")
|
||||
.WriteLine("/// </summary>");
|
||||
}
|
||||
|
||||
builder
|
||||
.WriteLine("[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]")
|
||||
.WriteLine($"public sealed class {AttributeName}Attribute : Attribute")
|
||||
.WriteOpeningBracket();
|
||||
|
||||
builder
|
||||
.WriteLine($"public {AttributeName}Attribute(Type returnType){"{}"}")
|
||||
.WriteLine();
|
||||
|
||||
builder
|
||||
.WriteClosingBracket() // class
|
||||
.WriteClosingBracket(); // namespace
|
||||
|
||||
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
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 createType = null, Type returnType = null){"{}"}")
|
||||
.WriteLine();
|
||||
|
||||
builder
|
||||
.WriteClosingBracket() // class
|
||||
.WriteClosingBracket(); // namespace
|
||||
|
||||
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,495 +0,0 @@
|
|||
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;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using CSharpExtensions = Microsoft.CodeAnalysis.CSharpExtensions;
|
||||
|
||||
#pragma warning disable CS8602
|
||||
|
||||
namespace MapTo
|
||||
{
|
||||
internal class EfGeneratorContext
|
||||
{
|
||||
private readonly List<SymbolDisplayPart> _ignoredNamespaces;
|
||||
|
||||
|
||||
public ImmutableArray<Diagnostic> Diagnostics { get; private set; }
|
||||
public EfMethodsModel? Model { get; private set; }
|
||||
protected Compilation Compilation { get; }
|
||||
protected INamedTypeSymbol MappingContextTypeSymbol { get; }
|
||||
protected SourceGenerationOptions SourceGenerationOptions { get; }
|
||||
protected TypeDeclarationSyntax TypeSyntax { get; }
|
||||
|
||||
protected ImmutableArray<string> Usings { get; private set; }
|
||||
protected INamedTypeSymbol EfUpdateMethodsTypeSymbol { get; }
|
||||
protected INamedTypeSymbol EfAddMethodsTypeSymbol { get; }
|
||||
|
||||
|
||||
|
||||
protected EfGeneratorContext(
|
||||
Compilation compilation,
|
||||
SourceGenerationOptions sourceGenerationOptions,
|
||||
TypeDeclarationSyntax typeSyntax)
|
||||
{
|
||||
Compilation = compilation;
|
||||
_ignoredNamespaces = new();
|
||||
Diagnostics = ImmutableArray<Diagnostic>.Empty;
|
||||
Usings = ImmutableArray.Create("System", Constants.RootNamespace);
|
||||
SourceGenerationOptions = sourceGenerationOptions;
|
||||
TypeSyntax = typeSyntax;
|
||||
EfUpdateMethodsTypeSymbol = compilation.GetTypeByMetadataNameOrThrow(EfUpdateMethodsAttributeSource.FullyQualifiedName);
|
||||
EfAddMethodsTypeSymbol = compilation.GetTypeByMetadataNameOrThrow(EfAddMethodsAttributeSource.FullyQualifiedName);
|
||||
AddUsingIfRequired(sourceGenerationOptions.SupportNullableStaticAnalysis, "System.Diagnostics.CodeAnalysis");
|
||||
}
|
||||
|
||||
public static EfGeneratorContext Create(
|
||||
Compilation compilation,
|
||||
SourceGenerationOptions sourceGenerationOptions,
|
||||
TypeDeclarationSyntax typeSyntax)
|
||||
{
|
||||
EfGeneratorContext context = typeSyntax switch
|
||||
{
|
||||
ClassDeclarationSyntax => 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 != TypeSyntax.GetNamespace() && !Usings.Contains(ns))
|
||||
{
|
||||
Usings = Usings.Add(ns);
|
||||
}
|
||||
}
|
||||
|
||||
protected ImmutableArray<INamedTypeSymbol> GetEntityTypeSymbol(MemberDeclarationSyntax memberDeclarationSyntax, string attributeName, SemanticModel? semanticModel = null)
|
||||
{
|
||||
var attributeData = memberDeclarationSyntax.GetAttribute(attributeName);
|
||||
var sourceSymbol = GetEntityTypeSymbols(attributeData, semanticModel);
|
||||
return sourceSymbol;
|
||||
}
|
||||
|
||||
protected ImmutableArray<LiteralExpressionSyntax> GetEntityStringLiteralSymbol(MemberDeclarationSyntax memberDeclarationSyntax, string attributeName, SemanticModel? semanticModel = null)
|
||||
{
|
||||
var attributeData = memberDeclarationSyntax.GetAttribute(attributeName);
|
||||
var sourceSymbol = GetEntityStringLiteralSymbol(attributeData);
|
||||
return sourceSymbol;
|
||||
}
|
||||
|
||||
protected TypeInfo FindSecondTypeInfoOfMemberExpressionSyntax(SemanticModel semanticModel, SyntaxNode attributeSyntax)
|
||||
{
|
||||
semanticModel ??= Compilation.GetSemanticModel(attributeSyntax.SyntaxTree);
|
||||
var descendentNodes = attributeSyntax
|
||||
.DescendantNodes();
|
||||
|
||||
var expression = descendentNodes.OfType<MemberAccessExpressionSyntax>().FirstOrDefault()?.Expression;
|
||||
if (expression != null)
|
||||
{
|
||||
return semanticModel.GetTypeInfo(expression);
|
||||
}
|
||||
|
||||
return new TypeInfo();
|
||||
}
|
||||
|
||||
protected TypeInfo? FindFirstTypeInfoOfMemberExpressionSyntax(SemanticModel semanticModel, SyntaxNode attributeSyntax)
|
||||
{
|
||||
semanticModel ??= Compilation.GetSemanticModel(attributeSyntax.SyntaxTree);
|
||||
var descendentNodes = attributeSyntax
|
||||
.DescendantNodes();
|
||||
|
||||
// Get the type of the key member id
|
||||
var expression = descendentNodes.OfType<MemberAccessExpressionSyntax>().FirstOrDefault();
|
||||
if (expression != null)
|
||||
{
|
||||
return semanticModel.GetTypeInfo(expression);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected string ExtractNameOfMemberName(MemberDeclarationSyntax memberDeclarationSyntax, string attributeName, SemanticModel? semanticModel = null)
|
||||
{
|
||||
var attributeData = memberDeclarationSyntax.GetAttribute(attributeName);
|
||||
var sourceSymbol = ExtractNameOfMemberName(attributeData, semanticModel);
|
||||
return sourceSymbol;
|
||||
}
|
||||
|
||||
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 ImmutableArray<LiteralExpressionSyntax> GetEntityStringLiteralSymbol(SyntaxNode? attributeSyntax)
|
||||
{
|
||||
if (attributeSyntax is null)
|
||||
{
|
||||
return new ImmutableArray<LiteralExpressionSyntax>(){};
|
||||
}
|
||||
|
||||
var descendentNodes = attributeSyntax
|
||||
.DescendantNodes();
|
||||
|
||||
var sourceTypeExpressionSyntax = descendentNodes
|
||||
.OfType<LiteralExpressionSyntax>()
|
||||
.ToImmutableArray();
|
||||
|
||||
|
||||
return sourceTypeExpressionSyntax;
|
||||
}
|
||||
|
||||
protected string ExtractNameOfMemberName(SyntaxNode? attributeSyntax, SemanticModel semanticModel)
|
||||
{
|
||||
if (attributeSyntax is null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var descendentNodes = attributeSyntax
|
||||
.DescendantNodes();
|
||||
|
||||
var idNode = descendentNodes.OfType<InvocationExpressionSyntax>()
|
||||
.FirstOrDefault()
|
||||
?.ChildNodesAndTokens()
|
||||
.FirstOrDefault(x => x.IsKind(SyntaxKind.ArgumentList))
|
||||
.ChildNodesAndTokens()
|
||||
.FirstOrDefault(x => x.IsKind(SyntaxKind.Argument))
|
||||
.ChildNodesAndTokens()
|
||||
.FirstOrDefault()
|
||||
.ChildNodesAndTokens()
|
||||
.LastOrDefault();
|
||||
|
||||
return idNode != null ? idNode.ToString() : String.Empty;
|
||||
}
|
||||
|
||||
|
||||
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 ImmutableArray<MemberDeclarationSyntax> GetAllowedMemberSyntaxes(string attributeName)
|
||||
{
|
||||
var classDeclarationSyntax = TypeSyntax;
|
||||
|
||||
var syntaxes = classDeclarationSyntax.DescendantNodes()
|
||||
.OfType<MemberDeclarationSyntax>()
|
||||
.Where(x => x
|
||||
.DescendantNodes()
|
||||
.OfType<AttributeSyntax>().Any(syntax =>
|
||||
syntax.Name.ToString() == attributeName))
|
||||
.ToImmutableArray();
|
||||
|
||||
return syntaxes;
|
||||
}
|
||||
|
||||
private EfMethodsModel? CreateMappingModel()
|
||||
{
|
||||
var semanticModel = Compilation.GetSemanticModel(TypeSyntax.SyntaxTree);
|
||||
|
||||
// get containing class type information
|
||||
ClassDeclarationSyntax classDeclarationSyntax = TypeSyntax as ClassDeclarationSyntax;
|
||||
|
||||
// context name
|
||||
var dbContextName = classDeclarationSyntax.Identifier.ValueText;
|
||||
var namespaceDeclaration = classDeclarationSyntax.Parent as NamespaceDeclarationSyntax;
|
||||
var contextNamespace = namespaceDeclaration.Name.ToString();
|
||||
var contextTypeFullName = $"{contextNamespace}.{dbContextName}";
|
||||
|
||||
|
||||
|
||||
// handles different attributes
|
||||
var addAttributeSymbols = GetAllowedMemberSyntaxes(EfAddMethodsAttributeSource.AttributeName);
|
||||
var updateAttributesMembers = GetAllowedMemberSyntaxes(EfUpdateMethodsAttributeSource.AttributeName);
|
||||
var getOneAttributesMembers = GetAllowedMemberSyntaxes(EfGetOneByAttributeSource.AttributeName);
|
||||
var getOneWithAttributesMembers = GetAllowedMemberSyntaxes(EfGetOneAttributeSource.AttributeName);
|
||||
var getManyWithAttributesMembers = GetAllowedMemberSyntaxes(EfGetManyAttributeSource.AttributeName);
|
||||
|
||||
|
||||
|
||||
List<EfEntityDataModel> methodsModels = new List<EfEntityDataModel>();
|
||||
|
||||
foreach (var uProperty in getOneAttributesMembers)
|
||||
{
|
||||
var entityDataModel = GetEntityData(uProperty, semanticModel);
|
||||
var newUpdateModel = ExtractEfGetEntityByModel(uProperty, semanticModel, entityDataModel);
|
||||
methodsModels.Add(newUpdateModel);
|
||||
}
|
||||
|
||||
|
||||
foreach (var uProperty in addAttributeSymbols)
|
||||
{
|
||||
var entityDataModel = GetEntityData(uProperty, semanticModel);
|
||||
var newAddModel = ExtractEfAddMethodsModel(semanticModel, uProperty, entityDataModel);
|
||||
methodsModels.Add(newAddModel);
|
||||
}
|
||||
|
||||
foreach (var uProperty in updateAttributesMembers)
|
||||
{
|
||||
var entityDataModel = GetEntityData(uProperty, semanticModel);
|
||||
var newUpdateModel = ExtractEfUpdateMethodsModel(uProperty, semanticModel, entityDataModel);
|
||||
methodsModels.Add(newUpdateModel);
|
||||
}
|
||||
|
||||
|
||||
foreach (var uProperty in getOneWithAttributesMembers)
|
||||
{
|
||||
var entityDataModel = GetEntityData(uProperty, semanticModel);
|
||||
var newUpdateModel = ExtractEfGetEntityWithModel(uProperty, semanticModel, entityDataModel);
|
||||
methodsModels.Add(newUpdateModel);
|
||||
}
|
||||
|
||||
|
||||
foreach (var uProperty in getManyWithAttributesMembers)
|
||||
{
|
||||
var entityDataModel = GetEntityData(uProperty, semanticModel);
|
||||
var newUpdateModel = ExtractEfGetManyModel(uProperty, semanticModel, entityDataModel);
|
||||
methodsModels.Add(newUpdateModel);
|
||||
}
|
||||
|
||||
|
||||
//SpinWait.SpinUntil(() => Debugger.IsAttached);
|
||||
|
||||
return new EfMethodsModel(
|
||||
SourceGenerationOptions,
|
||||
contextNamespace,
|
||||
dbContextName, contextTypeFullName,
|
||||
methodsModels.ToImmutableArray(),
|
||||
Usings);
|
||||
}
|
||||
|
||||
private static EfEntityDataModel GetEntityData(MemberDeclarationSyntax uProperty, SemanticModel semanticModel)
|
||||
{
|
||||
var entityTypeData = GetEntityTypeData(uProperty, semanticModel);
|
||||
string entityIdentifierName = entityTypeData.Name;
|
||||
string entityFullName = entityTypeData.ToDisplayString();
|
||||
var propertyNamex = (uProperty as PropertyDeclarationSyntax).Identifier.ValueText;
|
||||
return new EfEntityDataModel(propertyNamex, entityFullName, entityIdentifierName);
|
||||
}
|
||||
|
||||
private EfAddMethodsModel ExtractEfAddMethodsModel(SemanticModel semanticModel, MemberDeclarationSyntax memberSyntax, EfEntityDataModel efEntityDataModel)
|
||||
{
|
||||
var efAddAttributeTypeSymbols =
|
||||
GetEntityTypeSymbol(memberSyntax, EfAddMethodsAttributeSource.AttributeName, semanticModel);
|
||||
|
||||
string createTypeIdentifierName = efEntityDataModel.EntityTypeIdentifierName;
|
||||
string createTypeFullName = efEntityDataModel.EntityTypeFullName;
|
||||
string returnTypeIdentifierName = efEntityDataModel.EntityTypeIdentifierName;
|
||||
string returnTypeFullName = efEntityDataModel.EntityTypeFullName;
|
||||
|
||||
|
||||
if (efAddAttributeTypeSymbols.Length > 0)
|
||||
{
|
||||
createTypeIdentifierName = efAddAttributeTypeSymbols[0].Name;
|
||||
createTypeFullName = efAddAttributeTypeSymbols[0].ToDisplayString();
|
||||
}
|
||||
|
||||
if (efAddAttributeTypeSymbols.Length > 1)
|
||||
{
|
||||
returnTypeIdentifierName = efAddAttributeTypeSymbols[1].Name;
|
||||
returnTypeFullName = efAddAttributeTypeSymbols[1].ToDisplayString();
|
||||
}
|
||||
|
||||
|
||||
return new EfAddMethodsModel(efEntityDataModel, createTypeFullName, createTypeIdentifierName, returnTypeFullName,
|
||||
returnTypeIdentifierName);
|
||||
}
|
||||
|
||||
private EfUpdateMethodsModel ExtractEfUpdateMethodsModel(MemberDeclarationSyntax uProperty, SemanticModel semanticModel, EfEntityDataModel entityDataModel)
|
||||
{
|
||||
var efAddAttributeTypeSymbols =
|
||||
GetEntityTypeSymbol(uProperty, EfUpdateMethodsAttributeSource.AttributeName, semanticModel);
|
||||
|
||||
var keyPropertyName = ExtractNameOfMemberName(uProperty, EfUpdateMethodsAttributeSource.AttributeName, semanticModel);
|
||||
var keyMemberType = FindFirstTypeInfoOfMemberExpressionSyntax(semanticModel, TypeSyntax);
|
||||
//var secondTypeInfo = FindSecondTypeInfoOfMemberExpressionSyntax(semanticModel, TypeSyntax);
|
||||
|
||||
var keyMemberFullName = keyMemberType.Value.Type.ToDisplayString();
|
||||
//var keyMemberName = keyMemberType.Value.Type.Name;
|
||||
|
||||
// Try grabbing string literal if there's no nameof in it
|
||||
if (keyPropertyName == string.Empty)
|
||||
{
|
||||
keyPropertyName = GetEntityStringLiteralSymbol(TypeSyntax, EfUpdateMethodsAttributeSource.AttributeName, semanticModel)
|
||||
.FirstOrDefault()?
|
||||
.Token.ValueText ?? "Id";
|
||||
}
|
||||
|
||||
if (efAddAttributeTypeSymbols == null) return null;
|
||||
|
||||
string updateTypeIdentifierName = entityDataModel.EntityTypeIdentifierName;
|
||||
string updateTypeFullName = entityDataModel.EntityTypeFullName;
|
||||
string returnTypeIdentifierName = entityDataModel.EntityTypeIdentifierName;
|
||||
string returnTypeFullName = entityDataModel.EntityTypeFullName;
|
||||
|
||||
if (efAddAttributeTypeSymbols.Length > 0)
|
||||
{
|
||||
updateTypeIdentifierName = efAddAttributeTypeSymbols[0].Name;
|
||||
updateTypeFullName = efAddAttributeTypeSymbols[0].ToDisplayString();
|
||||
}
|
||||
|
||||
// Grab return type from attribute argument
|
||||
if (efAddAttributeTypeSymbols.Length > 1)
|
||||
{
|
||||
returnTypeIdentifierName = efAddAttributeTypeSymbols[1].Name;
|
||||
returnTypeFullName = efAddAttributeTypeSymbols[1].ToDisplayString();
|
||||
}
|
||||
|
||||
|
||||
return new EfUpdateMethodsModel(entityDataModel, updateTypeFullName, updateTypeIdentifierName, returnTypeFullName,
|
||||
returnTypeIdentifierName, keyPropertyName, keyMemberFullName);
|
||||
}
|
||||
|
||||
private EfGetOneWithModel ExtractEfGetEntityWithModel(MemberDeclarationSyntax uProperty, SemanticModel semanticModel, EfEntityDataModel entityDataModel)
|
||||
{
|
||||
|
||||
var efTypeofSymbols =GetEntityTypeSymbol(uProperty, EfGetOneByAttributeSource.AttributeName, semanticModel);
|
||||
if (efTypeofSymbols == null) return null;
|
||||
|
||||
string returnTypeIdentifierName = entityDataModel.EntityTypeIdentifierName;
|
||||
string returnTypeFullName = entityDataModel.EntityTypeFullName;
|
||||
|
||||
|
||||
// Grab return type from attribute argument
|
||||
if (efTypeofSymbols.Length > 0)
|
||||
{
|
||||
returnTypeIdentifierName = efTypeofSymbols[0].Name;
|
||||
returnTypeFullName = efTypeofSymbols[0].ToDisplayString();
|
||||
}
|
||||
|
||||
|
||||
return new EfGetOneWithModel(entityDataModel, returnTypeFullName, returnTypeIdentifierName);
|
||||
}
|
||||
|
||||
|
||||
private EfGetManyModel ExtractEfGetManyModel(MemberDeclarationSyntax uProperty, SemanticModel semanticModel, EfEntityDataModel entityDataModel)
|
||||
{
|
||||
|
||||
var efTypeofSymbols =GetEntityTypeSymbol(uProperty, EfGetOneByAttributeSource.AttributeName, semanticModel);
|
||||
if (efTypeofSymbols == null) return null;
|
||||
|
||||
string returnTypeIdentifierName = entityDataModel.EntityTypeIdentifierName;
|
||||
string returnTypeFullName = entityDataModel.EntityTypeFullName;
|
||||
|
||||
|
||||
// Grab return type from attribute argument
|
||||
if (efTypeofSymbols.Length > 0)
|
||||
{
|
||||
returnTypeIdentifierName = efTypeofSymbols[0].Name;
|
||||
returnTypeFullName = efTypeofSymbols[0].ToDisplayString();
|
||||
}
|
||||
|
||||
|
||||
return new EfGetManyModel(entityDataModel, returnTypeFullName, returnTypeIdentifierName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private EfGetOneByModel ExtractEfGetEntityByModel(MemberDeclarationSyntax uProperty, SemanticModel semanticModel, EfEntityDataModel entityDataModel)
|
||||
{
|
||||
|
||||
var efTypeofSymbols = GetEntityTypeSymbol(uProperty, EfGetOneByAttributeSource.AttributeName, semanticModel);
|
||||
var byParamPropertyName = ExtractNameOfMemberName(uProperty, EfGetOneByAttributeSource.AttributeName, semanticModel);
|
||||
var keyMemberType = FindFirstTypeInfoOfMemberExpressionSyntax(semanticModel, TypeSyntax);
|
||||
|
||||
var byParamFullTypeName = keyMemberType.Value.Type.ToDisplayString();
|
||||
|
||||
// Try grabbing string literal if there's no nameof in it
|
||||
if (byParamPropertyName == string.Empty)
|
||||
{
|
||||
byParamPropertyName = GetEntityStringLiteralSymbol(TypeSyntax, EfGetOneByAttributeSource.AttributeName, semanticModel)
|
||||
.FirstOrDefault()?
|
||||
.Token.ValueText ?? "Id";
|
||||
}
|
||||
|
||||
if (efTypeofSymbols == null) return null;
|
||||
|
||||
string returnTypeIdentifierName = entityDataModel.EntityTypeIdentifierName;
|
||||
string returnTypeFullName = entityDataModel.EntityTypeFullName;
|
||||
|
||||
|
||||
// Grab return type from attribute argument
|
||||
if (efTypeofSymbols.Length > 0)
|
||||
{
|
||||
returnTypeIdentifierName = efTypeofSymbols[0].Name;
|
||||
returnTypeFullName = efTypeofSymbols[0].ToDisplayString();
|
||||
}
|
||||
|
||||
|
||||
return new EfGetOneByModel(entityDataModel, byParamPropertyName, byParamFullTypeName, returnTypeFullName, returnTypeIdentifierName);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
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>
|
||||
/// 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, EfGeneratorAttributeSource.Generate(options))
|
||||
.AddSource(ref context, EfAddMethodsAttributeSource.Generate(options))
|
||||
.AddSource(ref context, EfUpdateMethodsAttributeSource.Generate(options))
|
||||
.AddSource(ref context, EfGetOneByAttributeSource.Generate(options))
|
||||
.AddSource(ref context, EfGetOneAttributeSource.Generate(options))
|
||||
.AddSource(ref context, EfGetManyAttributeSource.Generate(options));
|
||||
|
||||
|
||||
if (context.SyntaxReceiver is EfMethodsSyntaxReceiver receiver && receiver.CandidateTypes.Any())
|
||||
{
|
||||
AddGeneratedExtensions(context, compilation, receiver.CandidateTypes, options);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddGeneratedExtensions(GeneratorExecutionContext context, Compilation compilation, IEnumerable<TypeDeclarationSyntax> candidateMembers, SourceGenerationOptions options)
|
||||
{
|
||||
string addSourceTemplate = GetCsxMethodTemplate(context, "AddToEntityTemplate");
|
||||
string updateSourceTemplate = GetCsxMethodTemplate(context, "UpdateEntityTemplate");
|
||||
string getOneByTemplate = GetCsxMethodTemplate(context, "GetOneByTemplate");
|
||||
string getOneWithByTemplate = GetCsxMethodTemplate(context, "GetOneTemplate");
|
||||
string getManyWithTemplate = GetCsxMethodTemplate(context, "GetManyTemplate");
|
||||
|
||||
|
||||
|
||||
foreach (var candidateMember in candidateMembers)
|
||||
{
|
||||
|
||||
var mappingContext = EfGeneratorContext.Create(compilation, options, candidateMember);
|
||||
|
||||
mappingContext.Diagnostics.ForEach(context.ReportDiagnostic);
|
||||
|
||||
if (mappingContext.Model is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var (source, hintName) = candidateMember switch
|
||||
{
|
||||
ClassDeclarationSyntax => EfMethodsSource.Generate(
|
||||
mappingContext.Model,
|
||||
addSourceTemplate,
|
||||
updateSourceTemplate,
|
||||
getOneByTemplate,
|
||||
getOneWithByTemplate,
|
||||
getManyWithTemplate),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
context.AddSource(hintName, source);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetCsxMethodTemplate(GeneratorExecutionContext context, string templateName)
|
||||
{
|
||||
return context
|
||||
.AdditionalFiles
|
||||
.FirstOrDefault(x => x.Path.Contains(templateName))?
|
||||
.GetText()?
|
||||
.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MapTo.Extensions;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using static MapTo.Sources.Constants;
|
||||
|
||||
namespace MapTo.Sources
|
||||
{
|
||||
internal static class EfMethodsSource
|
||||
{
|
||||
internal static SourceCode Generate(EfMethodsModel model,
|
||||
string addSourceTemplate,
|
||||
string updateSourceTemplate,
|
||||
string getOneBySourceTemplate,
|
||||
string getOneWithSourceTemplate,
|
||||
string getManyWithSourceTemplate
|
||||
)
|
||||
{
|
||||
using var builder = new SourceBuilder();
|
||||
|
||||
|
||||
var contextFullName = model.ContextFullType;
|
||||
|
||||
builder
|
||||
.WriteLine(GeneratedFilesHeader)
|
||||
.WriteUsings(model.Usings)
|
||||
.WriteLine("using Microsoft.EntityFrameworkCore;")
|
||||
.WriteLine("using System.Linq;")
|
||||
.WriteLine("using System.Linq.Expressions;")
|
||||
.WriteLine("using System.Threading.Tasks;")
|
||||
|
||||
.WriteLine()
|
||||
// Namespace declaration
|
||||
.WriteLine($"namespace {model.Namespace}")
|
||||
.WriteOpeningBracket()
|
||||
// Class declaration
|
||||
.WriteLine($"public static partial class {model.ContextTypeName}Extensions")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine();
|
||||
|
||||
|
||||
foreach (var methodModel in model.MethodsModels.OrderBy(x => x.PropertyName))
|
||||
{
|
||||
switch (methodModel)
|
||||
{
|
||||
case EfAddMethodsModel modl:
|
||||
builder
|
||||
.EfAddAddEntityMethod(model, modl, addSourceTemplate)
|
||||
.WriteLine();
|
||||
break;
|
||||
|
||||
case EfUpdateMethodsModel modl:
|
||||
builder
|
||||
.EfAddUpdateEntityMethod(model, modl, updateSourceTemplate)
|
||||
.WriteLine();
|
||||
break;
|
||||
|
||||
case EfGetOneByModel modl:
|
||||
builder
|
||||
.EfAddGetOneEntityByMethod(model, modl, getOneBySourceTemplate)
|
||||
.WriteLine();
|
||||
break;
|
||||
case EfGetManyModel modl:
|
||||
builder
|
||||
.EfAddGetManyWithMethod(model, modl, getManyWithSourceTemplate)
|
||||
.WriteLine();
|
||||
break;
|
||||
case EfGetOneWithModel modl:
|
||||
builder
|
||||
.EfAddGetOneEntityWithMethod(model, modl, getOneWithSourceTemplate)
|
||||
.WriteLine();
|
||||
break;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
builder
|
||||
// End class declaration
|
||||
.WriteClosingBracket()
|
||||
.WriteLine()
|
||||
// End namespace declaration
|
||||
.WriteClosingBracket();
|
||||
|
||||
var generatedCode = builder.ToString();
|
||||
var hintName = $"{model.ContextTypeName}Extensions.g.cs";
|
||||
return new(generatedCode, hintName);
|
||||
}
|
||||
|
||||
internal static SourceBuilder ParseTemplate(this SourceBuilder builder, string finalTemplate)
|
||||
{
|
||||
string[] array = finalTemplate.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
for (var i = 0; i < array.Length; i++)
|
||||
{
|
||||
var line = array[i];
|
||||
builder.WriteLine(line);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
using MapTo.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MapTo.Sources
|
||||
{
|
||||
internal static class EfAddEntityTemplateSource
|
||||
{
|
||||
internal static SourceBuilder EfAddAddEntityMethod(this SourceBuilder builder, EfMethodsModel methodsModel, EfAddMethodsModel model, string addSourceTemplate)
|
||||
{
|
||||
var returnTypeFullName = model.ReturnTypeFullName;
|
||||
var createTypeFullName = model.CreateTypeFullName;
|
||||
var newEntityVarName = $"new{model.EntityTypeIdentifierName}";
|
||||
var toCreateVarName = $"{model.EntityTypeIdentifierName.ToCamelCase()}ToCreate";
|
||||
|
||||
var entityTypeName = model.EntityTypeIdentifierName;
|
||||
var contextFullName = methodsModel.ContextFullType;
|
||||
var propertyName = model.PropertyName;
|
||||
|
||||
if (!addSourceTemplate.IsEmpty())
|
||||
{
|
||||
var templateToSourceBuilder = new StringBuilder(addSourceTemplate);
|
||||
templateToSourceBuilder
|
||||
.Replace("{entityTypeName}", model.EntityTypeIdentifierName)
|
||||
.Replace("{returnTypeFullName}", returnTypeFullName)
|
||||
.Replace("{createTypeFullName}", createTypeFullName)
|
||||
.Replace("{contextFullName}", contextFullName)
|
||||
.Replace("{toCreateVarName}", toCreateVarName)
|
||||
.Replace("{newEntityVarName}", newEntityVarName)
|
||||
.Replace("{entityTypeFullName}", model.EntityTypeFullName)
|
||||
.Replace("{propertyName}", propertyName);
|
||||
|
||||
builder
|
||||
.ParseTemplate(templateToSourceBuilder.ToString());
|
||||
}
|
||||
|
||||
if (addSourceTemplate.IsEmpty())
|
||||
{
|
||||
builder
|
||||
.WriteComment("Generated body")
|
||||
//.WriteLine(GeneratedFilesHeader)
|
||||
.WriteLine($"public static (bool, {model.ReturnTypeFullName}) Add{entityTypeName}(")
|
||||
.WriteLine($"this {contextFullName} dbContext,")
|
||||
.WriteLine($"{createTypeFullName} {toCreateVarName})")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine($"var {newEntityVarName} = new {model.EntityTypeFullName}({toCreateVarName});")
|
||||
.WriteLine($"dbContext.{propertyName}.Add({newEntityVarName});")
|
||||
.WriteLine($"var success = dbContext.SaveChanges() >= 0;")
|
||||
.WriteLine($"return (success, new {returnTypeFullName}({newEntityVarName}));")
|
||||
.WriteClosingBracket();
|
||||
|
||||
builder
|
||||
.WriteLine();
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
using MapTo.Extensions;
|
||||
using MapTo.Sources;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MapTo
|
||||
{
|
||||
internal static class EfGetOneEntityByTemplate
|
||||
{
|
||||
internal static SourceBuilder EfAddGetOneEntityByMethod(this SourceBuilder builder, EfMethodsModel methodsModel, EfGetOneByModel model, string addSourceTemplate)
|
||||
{
|
||||
var returnTypeFullName = model.ReturnTypeFullName;
|
||||
var entityTypeName = model.EntityTypeIdentifierName;
|
||||
var byParamPropertyName = model.ByParamPropertyName;
|
||||
var byParamFullType = model.ByParamFullTypeName;
|
||||
|
||||
var contextFullName = methodsModel.ContextFullType;
|
||||
var byParamVarName = model.ByParamPropertyName.ToCamelCase();
|
||||
var findEntityVarName = model.EntityTypeIdentifierName.ToCamelCase();
|
||||
var propertyName = model.PropertyName;
|
||||
|
||||
if (!addSourceTemplate.IsEmpty())
|
||||
{
|
||||
var templateToSourceBuilder = new StringBuilder(addSourceTemplate);
|
||||
templateToSourceBuilder
|
||||
.Replace("{returnTypeFullName}", returnTypeFullName)
|
||||
.Replace("{entityTypeName}", entityTypeName)
|
||||
.Replace("{byParamPropertyName}", byParamPropertyName)
|
||||
.Replace("{contextFullName}", contextFullName)
|
||||
.Replace("{contextFullName}", contextFullName)
|
||||
|
||||
.Replace("{byParamFullType}", byParamFullType)
|
||||
.Replace("{byParamVarName}", byParamVarName)
|
||||
.Replace("{findEntityVarName}", findEntityVarName)
|
||||
.Replace("{propertyName}", propertyName);
|
||||
|
||||
builder
|
||||
.ParseTemplate(templateToSourceBuilder.ToString());
|
||||
}
|
||||
|
||||
if (addSourceTemplate.IsEmpty())
|
||||
{
|
||||
builder
|
||||
.WriteComment("Generated body")
|
||||
//.WriteLine(GeneratedFilesHeader)
|
||||
.WriteLine($"public static (bool, {returnTypeFullName}) GetOne{entityTypeName}By{byParamPropertyName} (this {contextFullName} dbContext, {byParamFullType} {byParamVarName})")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine($"var {findEntityVarName} = dbContext.{propertyName}")
|
||||
.WriteLine($".Where(x => x.{byParamPropertyName} == {byParamVarName})")
|
||||
.WriteLine($".Select(x => new {returnTypeFullName}(x))")
|
||||
.WriteLine($".FirstOrDefault();")
|
||||
.WriteLine($"return ({findEntityVarName} != null, {findEntityVarName});")
|
||||
.WriteClosingBracket();
|
||||
|
||||
builder
|
||||
.WriteLine();
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
using MapTo.Extensions;
|
||||
using MapTo.Sources;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MapTo
|
||||
{
|
||||
internal static class EfGetOneWithTemplateSource
|
||||
{
|
||||
internal static SourceBuilder EfAddGetOneEntityWithMethod(this SourceBuilder builder, EfMethodsModel methodsModel, EfGetOneWithModel model, string addSourceTemplate)
|
||||
{
|
||||
var returnTypeFullName = model.ReturnTypeFullName;
|
||||
var entityTypeName = model.EntityTypeIdentifierName;
|
||||
|
||||
var contextFullName = methodsModel.ContextFullType;
|
||||
var findEntityVarName = model.EntityTypeIdentifierName.ToCamelCase();
|
||||
var propertyName = model.PropertyName;
|
||||
|
||||
if (!addSourceTemplate.IsEmpty())
|
||||
{
|
||||
var templateToSourceBuilder = new StringBuilder(addSourceTemplate);
|
||||
templateToSourceBuilder
|
||||
.Replace("{returnTypeFullName}", returnTypeFullName)
|
||||
.Replace("{entityTypeName}", entityTypeName)
|
||||
.Replace("{contextFullName}", contextFullName)
|
||||
.Replace("{contextFullName}", contextFullName)
|
||||
.Replace("{findEntityVarName}", findEntityVarName)
|
||||
.Replace("{propertyName}", propertyName);
|
||||
|
||||
builder
|
||||
.ParseTemplate(templateToSourceBuilder.ToString());
|
||||
}
|
||||
|
||||
if (addSourceTemplate.IsEmpty())
|
||||
{
|
||||
builder
|
||||
.WriteComment("Generated body")
|
||||
//.WriteLine(GeneratedFilesHeader)
|
||||
.WriteLine($"public static (bool, {returnTypeFullName}) GetOne{entityTypeName}With (this {contextFullName} dbContext, Expression<Func<{returnTypeFullName},bool>> with) ")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine($"var {findEntityVarName} =")
|
||||
.WriteLine($".Select(x => new {returnTypeFullName}(x))")
|
||||
.WriteLine($".FirstOrDefault(with);")
|
||||
.WriteLine()
|
||||
.WriteLine($"return ({findEntityVarName} != null, {findEntityVarName});")
|
||||
.WriteClosingBracket();
|
||||
|
||||
builder
|
||||
.WriteLine();
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
internal static SourceBuilder EfAddGetManyWithMethod(this SourceBuilder builder, EfMethodsModel methodsModel, EfGetManyModel model, string addSourceTemplate)
|
||||
{
|
||||
var returnTypeFullName = model.ReturnTypeFullName;
|
||||
var entityTypeName = model.EntityTypeIdentifierName;
|
||||
|
||||
var contextFullName = methodsModel.ContextFullType;
|
||||
var findEntityVarName = model.EntityTypeIdentifierName.ToCamelCase();
|
||||
var propertyName = model.PropertyName;
|
||||
|
||||
if (!addSourceTemplate.IsEmpty())
|
||||
{
|
||||
var templateToSourceBuilder = new StringBuilder(addSourceTemplate);
|
||||
templateToSourceBuilder
|
||||
.Replace("{returnTypeFullName}", returnTypeFullName)
|
||||
.Replace("{entityTypeName}", entityTypeName)
|
||||
.Replace("{contextFullName}", contextFullName)
|
||||
.Replace("{contextFullName}", contextFullName)
|
||||
.Replace("{findEntityVarName}", findEntityVarName)
|
||||
.Replace("{propertyName}", propertyName);
|
||||
|
||||
builder
|
||||
.ParseTemplate(templateToSourceBuilder.ToString());
|
||||
}
|
||||
|
||||
if (addSourceTemplate.IsEmpty())
|
||||
{
|
||||
builder
|
||||
.WriteComment("Generated body")
|
||||
//.WriteLine(GeneratedFilesHeader)
|
||||
.WriteLine($"public static (bool, ImmutableArray<{returnTypeFullName}>) Get{propertyName}(this {contextFullName}dbContext, Expression <Func<{returnTypeFullName}, bool> > where = null,")
|
||||
.WriteLine($"Expression <Func<{returnTypeFullName}, object> > orderBy = null, int skip = 0, int take = 50, int orderDir = 1)")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine($"var query = dbContext")
|
||||
.WriteLine($".{propertyName}")
|
||||
.WriteLine($".Select(x => new {returnTypeFullName}(x));")
|
||||
.WriteComment("limit take by 200 records")
|
||||
.WriteLine("if (take > 200) take = 200;")
|
||||
.WriteLine("query.Skip(skip).Take(take);")
|
||||
.WriteLine("if (where != null) query.Where(where);")
|
||||
.WriteLine("if (orderDir == 1) query.OrderBy(orderBy);")
|
||||
.WriteLine("else query.OrderByDescending(orderBy);")
|
||||
.WriteLine($"return query.ToImmutableArray();")
|
||||
.WriteClosingBracket();
|
||||
|
||||
builder
|
||||
.WriteLine();
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
using MapTo.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MapTo.Sources
|
||||
{
|
||||
internal static class EfUpdateEntityTemplateSource
|
||||
{
|
||||
internal static SourceBuilder EfAddUpdateEntityMethod(this SourceBuilder builder, EfMethodsModel methodsModel, EfUpdateMethodsModel model, string updateSourceTemplate)
|
||||
{
|
||||
var entityTypeName = model.EntityTypeIdentifierName;
|
||||
var contextFullName = methodsModel.ContextFullType;
|
||||
var propertyName = model.PropertyName;
|
||||
var returnTypeFullName = model.ReturnTypeFullName;
|
||||
var updateTypeFullName = model.UpdateTypeFullName;
|
||||
var updateVarName = $"{entityTypeName.ToCamelCase()}ToUpdate";
|
||||
var keyPropertyName = model.KeyPropertyName;
|
||||
var keyTypeFullName = model.KeyFullTypeName;
|
||||
var existingVarName = entityTypeName.ToCamelCase();
|
||||
var keyVarName = entityTypeName.ToCamelCase() + model.KeyPropertyName;
|
||||
if (!updateSourceTemplate.IsEmpty())
|
||||
{
|
||||
var templateToSourceBuilder = new StringBuilder(updateSourceTemplate);
|
||||
templateToSourceBuilder
|
||||
.Replace("{entityTypeName}", entityTypeName)
|
||||
.Replace("{returnTypeFullName}", returnTypeFullName)
|
||||
.Replace("{updateTypeFullName}", updateTypeFullName)
|
||||
.Replace("{updateVarName}", updateVarName)
|
||||
.Replace("{contextFullName}", contextFullName)
|
||||
.Replace("{propertyName}", propertyName)
|
||||
.Replace("{keyTypeFullName}", keyTypeFullName)
|
||||
.Replace("{keyPropertyName}", keyPropertyName)
|
||||
.Replace("{keyVarName}", keyVarName)
|
||||
.Replace("{existingEntityVarName}", existingVarName);
|
||||
builder
|
||||
.ParseTemplate(templateToSourceBuilder.ToString());
|
||||
}
|
||||
|
||||
if (updateSourceTemplate.IsEmpty())
|
||||
{
|
||||
builder
|
||||
.WriteComment("Generated body")
|
||||
.WriteLine($"public static (bool, {returnTypeFullName}) Update{entityTypeName}(")
|
||||
.WriteLine($"this {contextFullName} dbContext,")
|
||||
.WriteLine($"{updateTypeFullName} {updateVarName},")
|
||||
.WriteLine($"{keyTypeFullName} {keyVarName})")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine($"var {existingVarName} = dbContext.{propertyName}.FirstOrDefault(x => x.{keyPropertyName} == {keyVarName});")
|
||||
.WriteLine($"if ({existingVarName} == null) return (false, null);")
|
||||
.WriteLine($"var success = dbContext.SaveChanges() >= 0;")
|
||||
.WriteLine($"return (success, new {returnTypeFullName}({existingVarName}));")
|
||||
.WriteClosingBracket();
|
||||
|
||||
builder
|
||||
.WriteLine();
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MapTo.Sources;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace MapTo
|
||||
{
|
||||
internal enum EfMethodsAttributeType
|
||||
{
|
||||
Add,
|
||||
Update,
|
||||
Invalid
|
||||
}
|
||||
|
||||
internal record CandidateMember(
|
||||
MemberDeclarationSyntax MemberDeclarationSyntax,
|
||||
EfMethodsAttributeType AttributeType
|
||||
);
|
||||
|
||||
|
||||
internal class EfMethodsSyntaxReceiver : ISyntaxReceiver
|
||||
{
|
||||
public List<TypeDeclarationSyntax> CandidateTypes { get; } = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
{
|
||||
if (syntaxNode is not TypeDeclarationSyntax { AttributeLists: { Count: >= 1 } attributes } typeDeclarationSyntax)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var attributeSyntax = attributes
|
||||
.SelectMany(a => a.Attributes)
|
||||
.FirstOrDefault(a => a.Name is
|
||||
IdentifierNameSyntax { Identifier: { ValueText: EfGeneratorAttributeSource.AttributeName } }
|
||||
or
|
||||
QualifiedNameSyntax
|
||||
{
|
||||
Left: IdentifierNameSyntax { Identifier: { ValueText: Constants.RootNamespace } },
|
||||
Right: IdentifierNameSyntax { Identifier: { ValueText: EfGeneratorAttributeSource.AttributeName } }
|
||||
}
|
||||
);
|
||||
|
||||
if (attributeSyntax is not null)
|
||||
{
|
||||
CandidateTypes.Add(typeDeclarationSyntax);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ namespace MapTo.Tests.Infrastructure
|
|||
}
|
||||
|
||||
var driver = CSharpGeneratorDriver.Create(
|
||||
new List<ISourceGenerator>() { new MapToGenerator(), new EfMethodsGenerator() },
|
||||
new List<ISourceGenerator>() { new MapToGenerator()},
|
||||
optionsProvider: new TestAnalyzerConfigOptionsProvider(analyzerConfigOptions),
|
||||
parseOptions: new CSharpParseOptions(languageVersion)
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue