Get one template working

This commit is contained in:
CodeLiturgy 2022-09-05 03:58:28 +01:00
parent 9743ff3740
commit 32bf670b9e
7 changed files with 346 additions and 137 deletions

View File

@ -272,31 +272,39 @@ namespace MapTo
var addAttributeSymbols = GetAllowedMemberSyntaxes(EfAddMethodsAttributeSource.AttributeName);
var updateAttributesMembers = GetAllowedMemberSyntaxes(EfUpdateMethodsAttributeSource.AttributeName);
var getOneAttributesMembers = GetAllowedMemberSyntaxes(EfGetOneByAttributeSource.AttributeName);
List<IEfMethodsModel> methodsModels = new List<IEfMethodsModel>();
foreach (var uProperty in updateAttributesMembers)
List<EfEntityDataModel> methodsModels = new List<EfEntityDataModel>();
foreach (var uProperty in getOneAttributesMembers)
{
var newUpdateModel = ExtractEfUpdateMethodsModel(semanticModel, uProperty);
var newUpdateModel = ExtractEfGetEntityByModel(semanticModel, uProperty);
methodsModels.Add(newUpdateModel);
}
foreach (var uProperty in addAttributeSymbols)
{
var entityTypeData = GetEntityTypeData(uProperty, semanticModel);
string entityIdentifierName = entityTypeData.Name;
string entityFullName = entityTypeData.ToDisplayString();
var propertyNamex = (uProperty as PropertyDeclarationSyntax ).Identifier.ValueText;
var propertyNamex = (uProperty as PropertyDeclarationSyntax).Identifier.ValueText;
var entityDataModel = new EfEntityDataModel(propertyNamex, entityFullName, entityIdentifierName);
var newAddModel = ExtractEfAddMethodsModel(semanticModel, uProperty, entityDataModel);
methodsModels.Add(newAddModel);
}
foreach (var uProperty in updateAttributesMembers)
{
var newUpdateModel = ExtractEfUpdateMethodsModel(semanticModel, uProperty);
methodsModels.Add(newUpdateModel);
}
//SpinWait.SpinUntil(() => Debugger.IsAttached);
return new EfMethodsModel(
@ -390,6 +398,55 @@ namespace MapTo
return new EfUpdateMethodsModel(entityDataModel, updateTypeFullName, updateTypeIdentifierName, returnTypeFullName,
returnTypeIdentifierName, keyPropertyName, keyMemberFullName);
}
private EfGetOneByModel ExtractEfGetEntityByModel(SemanticModel semanticModel, MemberDeclarationSyntax uProperty)
{
//SpinWait.SpinUntil(() => Debugger.IsAttached);
var entityTypeData = GetEntityTypeData(uProperty, semanticModel);
string entityIdentifierName = entityTypeData.Name;
string entityFullName = entityTypeData.ToDisplayString();
var propertyNamex = (uProperty as PropertyDeclarationSyntax).Identifier.ValueText;
var entityDataModel = new EfEntityDataModel(propertyNamex, entityFullName, entityIdentifierName);
var efTypeofSymbols =
GetEntityTypeSymbol(uProperty, EfGetOneByAttributeSource.AttributeName, semanticModel);
var byParamPropertyName = ExtractNameOfMemberName(uProperty, EfGetOneByAttributeSource.AttributeName, semanticModel);
var keyMemberType = FindFirstTypeInfoOfMemberExpressionSyntax(semanticModel, TypeSyntax);
var secondTypeInfo = FindSecondTypeInfoOfMemberExpressionSyntax(semanticModel, TypeSyntax);
var byParamFullName = keyMemberType.Value.Type.ToDisplayString();
var byParamMemberName = keyMemberType.Value.Type.Name;
// 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, byParamFullName, returnTypeFullName, returnTypeIdentifierName);
}
protected ImmutableArray<IPropertySymbol> GetSymbolsFromAttribute(ITypeSymbol typeSymbol, INamedTypeSymbol attributeTypeSymbol)

View File

@ -68,7 +68,7 @@ namespace MapTo
var (source, hintName) = candidateMember switch
{
ClassDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model, addSourceTemplate, updateSourceTemplate),
ClassDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model, addSourceTemplate, updateSourceTemplate, getOneByTemplate),
_ => throw new ArgumentOutOfRangeException()
};

View File

@ -11,7 +11,7 @@ namespace MapTo.Sources
{
internal static class EfMethodsSource
{
internal static SourceCode Generate(EfMethodsModel model, string addSourceTemplate, string updateSourceTemplate)
internal static SourceCode Generate(EfMethodsModel model, string addSourceTemplate, string updateSourceTemplate, string getOneBySourceTemplate)
{
using var builder = new SourceBuilder();
@ -35,7 +35,8 @@ namespace MapTo.Sources
.WriteOpeningBracket()
.WriteLine();
foreach (var methodModel in model.MethodsModels)
foreach (var methodModel in model.MethodsModels.OrderBy(x => x.PropertyName))
{
if (methodModel is EfAddMethodsModel m)
{
@ -52,6 +53,14 @@ namespace MapTo.Sources
.WriteLine();
continue;
}
if (methodModel is EfGetOneByModel getOneByModel)
{
builder
.EfAddGetOneEntityByMethod(model, getOneByModel, getOneBySourceTemplate)
.WriteLine();
continue;
}
}
@ -67,7 +76,7 @@ namespace MapTo.Sources
return new(generatedCode, hintName);
}
private static SourceBuilder ParseTemplate(this SourceBuilder builder, string finalTemplate)
internal static SourceBuilder ParseTemplate(this SourceBuilder builder, string finalTemplate)
{
string[] array = finalTemplate.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
@ -80,107 +89,7 @@ namespace MapTo.Sources
return builder;
}
private static SourceBuilder EfAddAddEntityMethod(this SourceBuilder builder, EfMethodsModel methodsModel, EfAddMethodsModel model, string addSourceTemplate)
{
var returnTypeFullName = model.ReturnTypeFullName;
var createTypeFullName = model.CreateTypeFullName;
var newEntityVarName = $"new{model.Entity.EntityTypeIdentifierName}";
var toCreateVarName = $"{model.Entity.EntityTypeIdentifierName.ToCamelCase()}ToCreate";
var entityTypeName = model.Entity.EntityTypeIdentifierName;
var contextFullName = methodsModel.ContextFullType;
var propertyName = model.Entity.PropertyName;
if (!addSourceTemplate.IsEmpty())
{
var templateToSourceBuilder = new StringBuilder(addSourceTemplate);
templateToSourceBuilder
.Replace("{entityTypeName}", model.Entity.EntityTypeIdentifierName)
.Replace("{returnTypeFullName}", returnTypeFullName)
.Replace("{createTypeFullName}", createTypeFullName)
.Replace("{contextFullName}", contextFullName)
.Replace("{toCreateVarName}", toCreateVarName)
.Replace("{newEntityVarName}", newEntityVarName)
.Replace("{entityTypeFullName}", model.Entity.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.Entity.EntityTypeFullName}({toCreateVarName});")
.WriteLine($"dbContext.{propertyName}.Add({newEntityVarName});")
.WriteLine($"var success = dbContext.SaveChanges() >= 0;")
.WriteLine($"return (success, new {returnTypeFullName}({newEntityVarName}));")
.WriteClosingBracket();
builder
.WriteLine();
}
return builder;
}
private static SourceBuilder EfAddUpdateEntityMethod(this SourceBuilder builder, EfMethodsModel methodsModel, EfUpdateMethodsModel model, string updateSourceTemplate)
{
var entityTypeName = model.Entity.EntityTypeIdentifierName;
var contextFullName = methodsModel.ContextFullType;
var propertyName = model.Entity.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;
}
}

View File

@ -0,0 +1,60 @@
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;
}
}
}

View File

@ -0,0 +1,63 @@
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;
}
}
}

View File

@ -0,0 +1,62 @@
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;
}
}
}

View File

@ -78,34 +78,92 @@ namespace MapTo
string Namespace,
string ContextTypeName,
string ContextFullType,
ImmutableArray<IEfMethodsModel> MethodsModels,
ImmutableArray<EfEntityDataModel> MethodsModels,
ImmutableArray<string> Usings
);
internal record EfEntityDataModel(
string PropertyName,
string EntityTypeFullName,
string EntityTypeIdentifierName
);
internal record EfAddMethodsModel(
internal class EfEntityDataModel
{
public string PropertyName { get; set; }
public string EntityTypeFullName { get; set; }
public string EntityTypeIdentifierName { get; set; }
EfEntityDataModel Entity,
string CreateTypeFullName,
string CreateTypeIdentifierName,
string ReturnTypeFullName,
string ReturnTypeIdentifierName
) : IEfMethodsModel;
internal record EfUpdateMethodsModel(
EfEntityDataModel Entity,
string UpdateTypeFullName,
string UpdateTypeIdentifierName,
string ReturnTypeFullName,
string ReturnTypeIdentifierName,
public EfEntityDataModel(string propertyName, string entityTypeFullName, string entityTypeIdentifierName)
{
PropertyName = propertyName;
EntityTypeFullName = entityTypeFullName;
EntityTypeIdentifierName = entityTypeIdentifierName;
}
}
internal class EfAddMethodsModel : EfEntityDataModel
{
public string CreateTypeFullName { get; set; }
public string CreateTypeIdentifierName { get; set; }
public string ReturnTypeFullName { get; set; }
public string ReturnTypeIdentifierName { get; set; }
public EfAddMethodsModel(EfEntityDataModel entity, string createTypeFullName,
string createTypeIdentifierName,
string returnTypeFullName,
string returnTypeIdentifierName) : base(entity.PropertyName, entity.EntityTypeFullName, entity.EntityTypeIdentifierName)
{
CreateTypeFullName = createTypeFullName;
CreateTypeIdentifierName = createTypeIdentifierName;
ReturnTypeIdentifierName = returnTypeIdentifierName;
ReturnTypeFullName = returnTypeFullName;
}
}
internal class EfGetOneByModel : EfEntityDataModel
{
public string ByParamPropertyName { get; set; }
public string ByParamFullTypeName { get; set; }
public string ByParamTypeName { get; set; }
public string ReturnTypeIdentifierName { get; set; }
public string ReturnTypeFullName { get; set; }
public EfGetOneByModel(EfEntityDataModel entity, string byParamPropertyName,
string byParamFullTypeName,
string returnTypeFullName,
string returnTypeIdentifierName) : base(entity.PropertyName, entity.EntityTypeFullName, entity.EntityTypeIdentifierName)
{
ByParamPropertyName = byParamPropertyName;
ByParamFullTypeName = byParamFullTypeName;
ReturnTypeIdentifierName = returnTypeIdentifierName;
ReturnTypeFullName = returnTypeFullName;
ByParamTypeName = returnTypeFullName;
}
}
internal class EfUpdateMethodsModel : EfEntityDataModel
{
public string UpdateTypeFullName;
public string UpdateTypeIdentifierName;
public string ReturnTypeFullName;
public string ReturnTypeIdentifierName;
public string KeyPropertyName;
public string KeyFullTypeName;
public EfUpdateMethodsModel(EfEntityDataModel entity,
string updateTypeFullName,
string updateTypeIdentifierName,
string returnTypeFullName,
string returnTypeIdentifierName,
string keyPropertyName,
string keyFullTypeName
): IEfMethodsModel;
string keyFullTypeName) : base(entity.PropertyName, entity.EntityTypeFullName, entity.EntityTypeIdentifierName)
{
UpdateTypeFullName = updateTypeFullName;
UpdateTypeIdentifierName = updateTypeIdentifierName;
ReturnTypeFullName= returnTypeFullName;
ReturnTypeIdentifierName = returnTypeIdentifierName;
KeyPropertyName = keyPropertyName;
KeyFullTypeName = keyFullTypeName;
}
}
internal record SourceGenerationOptions(
AccessModifier ConstructorAccessModifier,
AccessModifier GeneratedMethodsAccessModifier,