Add GetOneFromListTemplate

This commit is contained in:
CodeLiturgy 2022-09-09 04:26:27 +01:00
parent 15a0f1a4f4
commit 2ac7524e8b
20 changed files with 251 additions and 15 deletions

View File

@ -4,7 +4,7 @@ using static BlueWest.EfMethods.Sources.Constants;
namespace BlueWest.Sources namespace BlueWest.Sources
{ {
public class EfGetListAttributeSource public static class EfGetListAttributeSource
{ {
internal const string AttributeName = "EfGetList"; internal const string AttributeName = "EfGetList";
internal const string AttributeClassName = AttributeName + "Attribute"; internal const string AttributeClassName = AttributeName + "Attribute";

View File

@ -0,0 +1,47 @@
using BlueWest.EfMethods.Sources;
using BlueWest.EfMethods;
using System;
using System.Collections.Generic;
using System.Text;
using static BlueWest.EfMethods.Sources.Constants;
namespace BlueWest.Sources
{
internal static class EfGetOneFromListAttributeSource
{
internal const string AttributeName = "EfGetOneFromList";
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();
builder
.WriteLine("/// <summary>")
.WriteLine("/// Attribute for generating a function to get many entities.")
.WriteLine("/// </summary>");
builder
.WriteLine("[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]")
.WriteLine($"public sealed class {AttributeName}Attribute : Attribute")
.WriteOpeningBracket();
builder
.WriteLine($"public {AttributeName}Attribute(string entityPrimaryKeyNameof, string listMemberNameof, string listPrimaryKeyNameof, Type returnType){"{}"}")
.WriteLine();
builder
.WriteClosingBracket() // class
.WriteClosingBracket(); // namespace
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
}
}
}

View File

@ -19,7 +19,7 @@ namespace BlueWest.EfMethods.Sources
builder builder
.WriteLine("/// <summary>") .WriteLine("/// <summary>")
.WriteLine("/// Generate update methods for this Db<Set> property") .WriteLine("/// Generate update methods this EF entity")
.WriteLine("/// </summary>"); .WriteLine("/// </summary>");
builder builder

View File

@ -276,6 +276,7 @@ namespace BlueWest.EfMethods
var efGetManyMembers = GetAllowedMemberSyntaxes(EfGetManyAttributeSource.AttributeName); var efGetManyMembers = GetAllowedMemberSyntaxes(EfGetManyAttributeSource.AttributeName);
var getListMembers = GetAllowedMemberSyntaxes(EfGetListAttributeSource.AttributeName); var getListMembers = GetAllowedMemberSyntaxes(EfGetListAttributeSource.AttributeName);
var getAddToListMembers = GetAllowedMemberSyntaxes(EfAddToListAttributeSource.AttributeName); var getAddToListMembers = GetAllowedMemberSyntaxes(EfAddToListAttributeSource.AttributeName);
var getOneFromListMembers = GetAllowedMemberSyntaxes(EfGetOneFromListAttributeSource.AttributeName);
@ -333,12 +334,14 @@ namespace BlueWest.EfMethods
var newModel = ExtractEfAddToListMethodsModel(uProperty, semanticModel, entityDataModel); var newModel = ExtractEfAddToListMethodsModel(uProperty, semanticModel, entityDataModel);
methodsModels.Add(newModel); methodsModels.Add(newModel);
} }
foreach (var uProperty in getOneFromListMembers)
{
var entityDataModel = GetEntityData(uProperty, semanticModel);
var newModel = ExtractEfGetOneFromListMethodsModel(uProperty, semanticModel, entityDataModel);
methodsModels.Add(newModel);
}
//SpinWait.SpinUntil(() => Debugger.IsAttached);
return new EfMethodsModel( return new EfMethodsModel(
SourceGenerationOptions, SourceGenerationOptions,
contextNamespace, contextNamespace,
@ -545,10 +548,7 @@ namespace BlueWest.EfMethods
private EfAddToListModel ExtractEfAddToListMethodsModel(MemberDeclarationSyntax uProperty, SemanticModel semanticModel, EfEntityDataModel entityDataModel) private EfAddToListModel ExtractEfAddToListMethodsModel(MemberDeclarationSyntax uProperty, SemanticModel semanticModel, EfEntityDataModel entityDataModel)
{ {
//SpinWait.SpinUntil(() => Debugger.IsAttached);
var efTypeofSymbols = GetEntityTypeSymbol(uProperty, EfAddToListAttributeSource.AttributeName, semanticModel);
var listPropertyName = ExtractNameOfMemberName(uProperty, EfAddToListAttributeSource.AttributeName, semanticModel); var listPropertyName = ExtractNameOfMemberName(uProperty, EfAddToListAttributeSource.AttributeName, semanticModel);
var keyPropertyName = ExtractNameOfMemberName(uProperty, EfAddToListAttributeSource.AttributeName, semanticModel, 1);; var keyPropertyName = ExtractNameOfMemberName(uProperty, EfAddToListAttributeSource.AttributeName, semanticModel, 1);;
@ -574,6 +574,8 @@ namespace BlueWest.EfMethods
var createTypeIdentifierName =listEntityIdentifierName; var createTypeIdentifierName =listEntityIdentifierName;
var createTypeFullName = listEntityFullTypeName; var createTypeFullName = listEntityFullTypeName;
var efTypeofSymbols = GetEntityTypeSymbol(uProperty, EfAddToListAttributeSource.AttributeName, semanticModel);
// Grab create type from attribute argument // Grab create type from attribute argument
if (efTypeofSymbols.Length > 0) if (efTypeofSymbols.Length > 0)
{ {
@ -601,6 +603,51 @@ namespace BlueWest.EfMethods
returnTypeFullName); returnTypeFullName);
} }
private EfGetOneFromListModel ExtractEfGetOneFromListMethodsModel(MemberDeclarationSyntax uProperty, SemanticModel semanticModel, EfEntityDataModel entityDataModel)
{
//SpinWait.SpinUntil(() => Debugger.IsAttached);
var efTypeofSymbols = GetEntityTypeSymbol(uProperty, EfGetOneFromListAttributeSource.AttributeName, semanticModel);
var attributeSymbol = uProperty.GetAttribute(EfGetOneFromListAttributeSource.AttributeName);
var keyPropertyName = ExtractNameOfMemberName(uProperty, EfGetOneFromListAttributeSource.AttributeName, semanticModel);
var listKeyPropertyName = ExtractNameOfMemberName(uProperty, EfGetOneFromListAttributeSource.AttributeName, semanticModel, 2);
var keyMemberType = FindTypeInfoOfMemberExpressionSyntax(semanticModel, attributeSymbol);
var listKeyTypeInfo = FindTypeInfoOfMemberExpressionSyntax(semanticModel, attributeSymbol, 0);
var keyFullTypeName = keyMemberType.Value.Type.ToDisplayString();
var listEntityTypeInfo = (FindTypeInfoOfMemberExpressionSyntax(semanticModel, attributeSymbol, 1).Value.Type as INamedTypeSymbol).TypeArguments.FirstOrDefault();
var listEntityIdentifierName = listEntityTypeInfo.Name;
var listEntityFullTypeName = listEntityTypeInfo.ToDisplayString();
var listKeyFullTypeName =listKeyTypeInfo.Value.Type.ToDisplayString();;
var listKeyTypeName = listKeyTypeInfo.Value.Type.Name;
var listPropertyName = ExtractNameOfMemberName(uProperty, EfGetOneFromListAttributeSource.AttributeName, semanticModel, 1);;
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 EfGetOneFromListModel(
entityDataModel,
listPropertyName,
listEntityIdentifierName,
listEntityFullTypeName,
keyPropertyName,
keyFullTypeName,
listKeyPropertyName,
listKeyFullTypeName,
listKeyTypeName,
returnTypeIdentifierName,
returnTypeFullName);
}
private static ITypeSymbol GetEntityTypeData(MemberDeclarationSyntax memberDeclarationSyntax, SemanticModel? semanticModel = null) private static ITypeSymbol GetEntityTypeData(MemberDeclarationSyntax memberDeclarationSyntax, SemanticModel? semanticModel = null)
{ {

View File

@ -39,7 +39,8 @@ namespace BlueWest.EfMethods
.AddSource(ref context, EfGetOneAttributeSource.Generate(options)) .AddSource(ref context, EfGetOneAttributeSource.Generate(options))
.AddSource(ref context, EfGetManyAttributeSource.Generate(options)) .AddSource(ref context, EfGetManyAttributeSource.Generate(options))
.AddSource(ref context, EfGetListAttributeSource.Generate(options)) .AddSource(ref context, EfGetListAttributeSource.Generate(options))
.AddSource(ref context, EfAddToListAttributeSource.Generate(options)); .AddSource(ref context, EfAddToListAttributeSource.Generate(options))
.AddSource(ref context, EfGetOneFromListAttributeSource.Generate(options));
@ -65,6 +66,8 @@ namespace BlueWest.EfMethods
string getManyWithTemplate = GetCsxMethodTemplate(context, "GetManyTemplate"); string getManyWithTemplate = GetCsxMethodTemplate(context, "GetManyTemplate");
string getListTemplate = GetCsxMethodTemplate(context, "GetListTemplate"); string getListTemplate = GetCsxMethodTemplate(context, "GetListTemplate");
string addToListTemplate = GetCsxMethodTemplate(context, "AddToListTemplate"); string addToListTemplate = GetCsxMethodTemplate(context, "AddToListTemplate");
string getOneFromListTemplate = GetCsxMethodTemplate(context, "GetOneFromListTemplate");
return new EfTemplates( return new EfTemplates(
addSourceTemplate, addSourceTemplate,
@ -73,7 +76,9 @@ namespace BlueWest.EfMethods
getOneTemplate, getOneTemplate,
getManyWithTemplate, getManyWithTemplate,
getListTemplate, getListTemplate,
addToListTemplate); addToListTemplate,
getOneFromListTemplate
);
} }
private static void AddGeneratedExtensions(GeneratorExecutionContext context, Compilation compilation, IEnumerable<TypeDeclarationSyntax> candidateMembers, SourceGenerationOptions options) private static void AddGeneratedExtensions(GeneratorExecutionContext context, Compilation compilation, IEnumerable<TypeDeclarationSyntax> candidateMembers, SourceGenerationOptions options)

View File

@ -64,6 +64,7 @@ namespace BlueWest.EfMethods.Sources
.EfAddGetOneMethod(model, currentModel, templates.GetOneTemplate) .EfAddGetOneMethod(model, currentModel, templates.GetOneTemplate)
.WriteLine(); .WriteLine();
break; break;
case EfGetListModel currentModel: case EfGetListModel currentModel:
builder builder
.EfAddGetListMethod(model, currentModel, templates.GetListTemplate) .EfAddGetListMethod(model, currentModel, templates.GetListTemplate)
@ -74,7 +75,13 @@ namespace BlueWest.EfMethods.Sources
.EfAddAddToListMethod(model, currentModel, templates.AddToListTemplate) .EfAddAddToListMethod(model, currentModel, templates.AddToListTemplate)
.WriteLine(); .WriteLine();
break; break;
case EfGetOneFromListModel currentModel:
builder
.EfAddGetOneFromListMethod(model, currentModel, templates.GetOneFromListTemplate)
.WriteLine();
break;
} }
} }

View File

@ -0,0 +1,79 @@
using BlueWest.EfMethods.Extensions;
using BlueWest.EfMethods.Sources;
using System;
using System.Collections.Generic;
using System.Text;
namespace BlueWest.EfMethods
{
internal static class EfGetOneFromListTemplateSource
{
internal static SourceBuilder EfAddGetOneFromListMethod(this SourceBuilder builder, EfMethodsModel methodsModel, EfGetOneFromListModel model, string addSourceTemplate)
{
var returnTypeFullName = model.ReturnTypeFullName;
var entityTypeName = model.EntityTypeIdentifierName;
var propertyName = model.PropertyName;
var listItemTypeName = model.ListEntityIdentifierName;
var contextFullName = methodsModel.ContextFullType;
var primaryKeyFullName = model.KeyFullTypeName;
var primaryKeyVarName = $"{model.EntityTypeIdentifierName}{model.KeyPropertyName}".ToCamelCase();
var listPrimaryKeyFullName = model.ListKeyFullTypeName;
var listPrimaryKeyVarName = $"{model.ListEntityIdentifierName}{model.ListKeyPropertyName}".ToCamelCase();
var listPropertyName = model.ListPropertyName;
var listPrimaryKeyPropertyName = model.ListKeyPropertyName;
var primaryKeyPropertyName = model.KeyPropertyName;
if (!addSourceTemplate.IsEmpty())
{
var templateToSourceBuilder = new StringBuilder(addSourceTemplate);
templateToSourceBuilder
.Replace("{returnTypeFullName}", returnTypeFullName)
.Replace("{entityTypeName}", entityTypeName)
.Replace("{listItemTypeName}", listItemTypeName)
.Replace("{contextFullName}", contextFullName)
.Replace("{primaryKeyPropertyName}", primaryKeyPropertyName)
.Replace("{listPrimaryKeyPropertyName}", listPrimaryKeyPropertyName)
.Replace("{primaryKeyFullName}", primaryKeyFullName)
.Replace("{primaryKeyVarName}", primaryKeyVarName)
.Replace("{listPrimaryKeyFullName}", listPrimaryKeyFullName)
.Replace("{listPrimaryKeyVarName}", listPrimaryKeyVarName)
.Replace("{listPropertyName}", listPropertyName)
.Replace("{propertyName}", propertyName);
builder
.ParseTemplate(templateToSourceBuilder.ToString());
}
if (addSourceTemplate.IsEmpty())
{
builder
.WriteComment("Generated body")
//.WriteLine(GeneratedFilesHeader)
.WriteLine($"public static (bool, {returnTypeFullName}) Get{listItemTypeName}From{entityTypeName} (this {contextFullName} dbContext, {primaryKeyFullName} {primaryKeyVarName},")
.WriteLine($"{listPrimaryKeyFullName} {listPrimaryKeyVarName})")
.WriteOpeningBracket()
.WriteLine($"var query =")
.WriteLine($"from mainEntity in dbContext.{propertyName}")
.WriteLine($"where mainEntity.{primaryKeyPropertyName} == {primaryKeyVarName}")
.WriteLine($"let list = mainEntity.{listPropertyName}")
.WriteLine($"from listItem in list")
.WriteLine($"where listItem.{listPrimaryKeyPropertyName} == {listPrimaryKeyVarName}")
.WriteLine($"select new {returnTypeFullName}(listItem);")
.WriteLine()
.WriteLine("query = countryQuery.SingleOrDefault();")
.WriteLine("return (query != null, query);")
.WriteClosingBracket();
builder
.WriteLine();
}
return builder;
}
}
}

View File

@ -40,7 +40,8 @@ namespace BlueWest.EfMethods
string GetOneTemplate, string GetOneTemplate,
string GetManyTemplate, string GetManyTemplate,
string GetListTemplate, string GetListTemplate,
string AddToListTemplate string AddToListTemplate,
string GetOneFromListTemplate
); );
internal class EfEntityDataModel internal class EfEntityDataModel
@ -222,6 +223,56 @@ namespace BlueWest.EfMethods
ReturnTypeFullName = returnTypeFullName; ReturnTypeFullName = returnTypeFullName;
} }
} }
internal class EfGetOneFromListModel : EfEntityDataModel
{
public string ListPropertyName { get; set; }
public string ListEntityIdentifierName { get; set; }
public string ListEntityFullTypeName { get; set; }
public string KeyPropertyName { get; set; }
public string KeyFullTypeName { get; set; }
public string ListKeyPropertyName { get; set; }
public string ListKeyFullTypeName { get; set; }
public string ListKeyTypeName { get; set; }
public string ReturnTypeIdentifierName { get; set; }
public string ReturnTypeFullName { get; set; }
public EfGetOneFromListModel(
EfEntityDataModel entity,
string listPropertyName,
string listEntityIdentifierName,
string listEntityFullTypeName,
string keyPropertyName,
string keyFullTypeName,
string listKeyPropertyName,
string listKeyFullTypeName,
string listKeyTypeName,
string returnTypeIdentifierName,
string returnTypeFullName)
: base(entity.PropertyName, entity.EntityTypeFullName, entity.EntityTypeIdentifierName)
{
ListPropertyName = listPropertyName;
ListEntityIdentifierName = listEntityIdentifierName;
ListEntityFullTypeName = listEntityFullTypeName;
KeyPropertyName = keyPropertyName;
KeyFullTypeName = keyFullTypeName;
ListKeyPropertyName = listKeyPropertyName;
ListKeyFullTypeName = listKeyFullTypeName;
ListKeyTypeName = listKeyTypeName;
ReturnTypeIdentifierName = returnTypeIdentifierName;
ReturnTypeFullName = returnTypeFullName;
}
}