From b8637c94abecb93168a6b94f59044c9e32ab66a5 Mon Sep 17 00:00:00 2001 From: CodeLiturgy Date: Mon, 5 Sep 2022 22:42:51 +0100 Subject: [PATCH] Using GetOne and GetMany templates --- .../EfGeneratorAttributeSource.cs | 0 .../EfGetManyAttributeSource.cs | 47 +++++ .../EfGetOneByAttributeSource.cs | 0 .../EfUpdateMethodsAttributeSource.cs | 4 +- .../GetOneWIthAttributeSource.cs | 47 +++++ .../EfMethods/EfAddMethodsAttributeSource.cs | 4 +- .../EfMethods/EfGeneratorContext.cs | 167 +++++++++--------- .../EfMethods/EfMethodsGenerator.cs | 16 +- .../EfMethods/EfMethodsSource.cs | 53 ++++-- .../EfGetOneWithTemplateSource.cs | 107 +++++++++++ src/BlueWest.MapTo/MapToGenerator.cs | 2 +- src/BlueWest.MapTo/Models.cs | 28 ++- 12 files changed, 369 insertions(+), 106 deletions(-) rename src/BlueWest.MapTo/EfMethods/{ => AttributeSources}/EfGeneratorAttributeSource.cs (100%) create mode 100644 src/BlueWest.MapTo/EfMethods/AttributeSources/EfGetManyAttributeSource.cs rename src/BlueWest.MapTo/EfMethods/{ => AttributeSources}/EfGetOneByAttributeSource.cs (100%) rename src/BlueWest.MapTo/EfMethods/{ => AttributeSources}/EfUpdateMethodsAttributeSource.cs (98%) create mode 100644 src/BlueWest.MapTo/EfMethods/AttributeSources/GetOneWIthAttributeSource.cs create mode 100644 src/BlueWest.MapTo/EfMethods/EfMethodsSource/EfGetOneWithTemplateSource.cs diff --git a/src/BlueWest.MapTo/EfMethods/EfGeneratorAttributeSource.cs b/src/BlueWest.MapTo/EfMethods/AttributeSources/EfGeneratorAttributeSource.cs similarity index 100% rename from src/BlueWest.MapTo/EfMethods/EfGeneratorAttributeSource.cs rename to src/BlueWest.MapTo/EfMethods/AttributeSources/EfGeneratorAttributeSource.cs diff --git a/src/BlueWest.MapTo/EfMethods/AttributeSources/EfGetManyAttributeSource.cs b/src/BlueWest.MapTo/EfMethods/AttributeSources/EfGetManyAttributeSource.cs new file mode 100644 index 0000000..5e854ec --- /dev/null +++ b/src/BlueWest.MapTo/EfMethods/AttributeSources/EfGetManyAttributeSource.cs @@ -0,0 +1,47 @@ +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("/// ") + .WriteLine("/// Attribute for generating a function to get one EF entity with a predicate as argument and a return type for the projection.") + .WriteLine("/// "); + } + + 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"); + } + } +} diff --git a/src/BlueWest.MapTo/EfMethods/EfGetOneByAttributeSource.cs b/src/BlueWest.MapTo/EfMethods/AttributeSources/EfGetOneByAttributeSource.cs similarity index 100% rename from src/BlueWest.MapTo/EfMethods/EfGetOneByAttributeSource.cs rename to src/BlueWest.MapTo/EfMethods/AttributeSources/EfGetOneByAttributeSource.cs diff --git a/src/BlueWest.MapTo/EfMethods/EfUpdateMethodsAttributeSource.cs b/src/BlueWest.MapTo/EfMethods/AttributeSources/EfUpdateMethodsAttributeSource.cs similarity index 98% rename from src/BlueWest.MapTo/EfMethods/EfUpdateMethodsAttributeSource.cs rename to src/BlueWest.MapTo/EfMethods/AttributeSources/EfUpdateMethodsAttributeSource.cs index 0167318..f112fa5 100644 --- a/src/BlueWest.MapTo/EfMethods/EfUpdateMethodsAttributeSource.cs +++ b/src/BlueWest.MapTo/EfMethods/AttributeSources/EfUpdateMethodsAttributeSource.cs @@ -7,7 +7,7 @@ namespace MapTo.Sources 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() @@ -29,7 +29,7 @@ namespace MapTo.Sources .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() diff --git a/src/BlueWest.MapTo/EfMethods/AttributeSources/GetOneWIthAttributeSource.cs b/src/BlueWest.MapTo/EfMethods/AttributeSources/GetOneWIthAttributeSource.cs new file mode 100644 index 0000000..6482796 --- /dev/null +++ b/src/BlueWest.MapTo/EfMethods/AttributeSources/GetOneWIthAttributeSource.cs @@ -0,0 +1,47 @@ +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("/// ") + .WriteLine("/// Attribute for generating a function to get one EF entity with a predicate as argument and a return type for the projection.") + .WriteLine("/// "); + } + + 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"); + } + } +} diff --git a/src/BlueWest.MapTo/EfMethods/EfAddMethodsAttributeSource.cs b/src/BlueWest.MapTo/EfMethods/EfAddMethodsAttributeSource.cs index c75c46f..552213d 100644 --- a/src/BlueWest.MapTo/EfMethods/EfAddMethodsAttributeSource.cs +++ b/src/BlueWest.MapTo/EfMethods/EfAddMethodsAttributeSource.cs @@ -32,9 +32,7 @@ namespace MapTo.Sources .WriteOpeningBracket(); builder - .WriteLine($"public {AttributeName}Attribute(Type createType = null, Type returnType = null)") - .WriteOpeningBracket() - .WriteClosingBracket() + .WriteLine($"public {AttributeName}Attribute(Type createType = null, Type returnType = null){"{}"}") .WriteLine(); builder diff --git a/src/BlueWest.MapTo/EfMethods/EfGeneratorContext.cs b/src/BlueWest.MapTo/EfMethods/EfGeneratorContext.cs index 96ffac9..c9aa572 100644 --- a/src/BlueWest.MapTo/EfMethods/EfGeneratorContext.cs +++ b/src/BlueWest.MapTo/EfMethods/EfGeneratorContext.cs @@ -21,22 +21,14 @@ namespace MapTo public ImmutableArray 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 Usings { get; private set; } - - protected INamedTypeSymbol EfUpdateMethodsTypeSymbol { get; } - protected INamedTypeSymbol EfAddMethodsTypeSymbol { get; } @@ -219,7 +211,6 @@ namespace MapTo protected bool IsEnumerable(ISymbol property, out INamedTypeSymbol? namedTypeSymbolResult) { - if (!property.TryGetTypeSymbol(out var propertyType)) { AddDiagnostic(DiagnosticsFactory.NoMatchingPropertyTypeFoundError(property)); @@ -241,7 +232,7 @@ namespace MapTo private ImmutableArray GetAllowedMemberSyntaxes(string attributeName) { - ClassDeclarationSyntax classDeclarationSyntax = TypeSyntax as ClassDeclarationSyntax; + var classDeclarationSyntax = TypeSyntax; var syntaxes = classDeclarationSyntax.DescendantNodes() .OfType() @@ -265,44 +256,58 @@ namespace MapTo 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 methodsModels = new List(); foreach (var uProperty in getOneAttributesMembers) { - var newUpdateModel = ExtractEfGetEntityByModel(semanticModel, uProperty); + var entityDataModel = GetEntityData(uProperty, semanticModel); + var newUpdateModel = ExtractEfGetEntityByModel(uProperty, semanticModel, entityDataModel); 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 entityDataModel = new EfEntityDataModel(propertyNamex, entityFullName, entityIdentifierName); + var entityDataModel = GetEntityData(uProperty, semanticModel); var newAddModel = ExtractEfAddMethodsModel(semanticModel, uProperty, entityDataModel); methodsModels.Add(newAddModel); } foreach (var uProperty in updateAttributesMembers) { - var newUpdateModel = ExtractEfUpdateMethodsModel(semanticModel, uProperty); + 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); @@ -315,6 +320,15 @@ namespace MapTo 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 = @@ -343,28 +357,17 @@ namespace MapTo returnTypeIdentifierName); } - private EfUpdateMethodsModel ExtractEfUpdateMethodsModel(SemanticModel semanticModel, MemberDeclarationSyntax uProperty) + private EfUpdateMethodsModel ExtractEfUpdateMethodsModel(MemberDeclarationSyntax uProperty, SemanticModel semanticModel, EfEntityDataModel entityDataModel) { - 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 efAddAttributeTypeSymbols = GetEntityTypeSymbol(uProperty, EfUpdateMethodsAttributeSource.AttributeName, semanticModel); var keyPropertyName = ExtractNameOfMemberName(uProperty, EfUpdateMethodsAttributeSource.AttributeName, semanticModel); - var keyMemberType = FindFirstTypeInfoOfMemberExpressionSyntax(semanticModel, TypeSyntax); - - var secondTypeInfo = FindSecondTypeInfoOfMemberExpressionSyntax(semanticModel, TypeSyntax); - - - + //var secondTypeInfo = FindSecondTypeInfoOfMemberExpressionSyntax(semanticModel, TypeSyntax); var keyMemberFullName = keyMemberType.Value.Type.ToDisplayString(); - var keyMemberName = keyMemberType.Value.Type.Name; + //var keyMemberName = keyMemberType.Value.Type.Name; // Try grabbing string literal if there's no nameof in it if (keyPropertyName == string.Empty) @@ -399,29 +402,59 @@ namespace MapTo returnTypeIdentifierName, keyPropertyName, keyMemberFullName); } - private EfGetOneByModel ExtractEfGetEntityByModel(SemanticModel semanticModel, MemberDeclarationSyntax uProperty) + private EfGetOneWithModel ExtractEfGetEntityWithModel(MemberDeclarationSyntax uProperty, SemanticModel semanticModel, EfEntityDataModel entityDataModel) { - //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); + if (efTypeofSymbols == null) return null; + + string returnTypeIdentifierName = entityDataModel.EntityTypeIdentifierName; + string returnTypeFullName = entityDataModel.EntityTypeFullName; + - var efTypeofSymbols = - GetEntityTypeSymbol(uProperty, EfGetOneByAttributeSource.AttributeName, semanticModel); + // 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 secondTypeInfo = FindSecondTypeInfoOfMemberExpressionSyntax(semanticModel, TypeSyntax); - - - - var byParamFullName = keyMemberType.Value.Type.ToDisplayString(); - var byParamMemberName = keyMemberType.Value.Type.Name; + var byParamFullTypeName = keyMemberType.Value.Type.ToDisplayString(); // Try grabbing string literal if there's no nameof in it if (byParamPropertyName == string.Empty) @@ -445,19 +478,10 @@ namespace MapTo } - return new EfGetOneByModel(entityDataModel, byParamPropertyName, byParamFullName, returnTypeFullName, returnTypeIdentifierName); - } - - - protected ImmutableArray GetSymbolsFromAttribute(ITypeSymbol typeSymbol, INamedTypeSymbol attributeTypeSymbol) - { - return typeSymbol - .GetAllMembers() - .OfType() - .Where(p => p.HasAttribute(attributeTypeSymbol)) - .ToImmutableArray()!; + return new EfGetOneByModel(entityDataModel, byParamPropertyName, byParamFullTypeName, returnTypeFullName, returnTypeIdentifierName); } + private static ITypeSymbol GetEntityTypeData(MemberDeclarationSyntax memberDeclarationSyntax, SemanticModel? semanticModel = null) { var member = (memberDeclarationSyntax as PropertyDeclarationSyntax).Type; @@ -467,20 +491,5 @@ namespace MapTo return firstTypeArgument; } - - - private string? ToQualifiedDisplayName(ISymbol? symbol) - { - if (symbol is null) - { - return null; - } - - var containingNamespace = TypeSyntax.GetNamespace(); - var symbolNamespace = symbol.ContainingNamespace.ToDisplayString(); - return containingNamespace != symbolNamespace && _ignoredNamespaces.Contains(symbol.ContainingNamespace.ToDisplayParts().First()) - ? symbol.ToDisplayString() - : symbol.Name; - } } } \ No newline at end of file diff --git a/src/BlueWest.MapTo/EfMethods/EfMethodsGenerator.cs b/src/BlueWest.MapTo/EfMethods/EfMethodsGenerator.cs index f0fd11d..8685271 100644 --- a/src/BlueWest.MapTo/EfMethods/EfMethodsGenerator.cs +++ b/src/BlueWest.MapTo/EfMethods/EfMethodsGenerator.cs @@ -33,7 +33,9 @@ namespace MapTo .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, EfGetOneByAttributeSource.Generate(options)) + .AddSource(ref context, EfGetOneAttributeSource.Generate(options)) + .AddSource(ref context, EfGetManyAttributeSource.Generate(options)); if (context.SyntaxReceiver is EfMethodsSyntaxReceiver receiver && receiver.CandidateTypes.Any()) @@ -53,6 +55,10 @@ namespace MapTo 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) { @@ -68,7 +74,13 @@ namespace MapTo var (source, hintName) = candidateMember switch { - ClassDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model, addSourceTemplate, updateSourceTemplate, getOneByTemplate), + ClassDeclarationSyntax => EfMethodsSource.Generate( + mappingContext.Model, + addSourceTemplate, + updateSourceTemplate, + getOneByTemplate, + getOneWithByTemplate, + getManyWithTemplate), _ => throw new ArgumentOutOfRangeException() }; diff --git a/src/BlueWest.MapTo/EfMethods/EfMethodsSource.cs b/src/BlueWest.MapTo/EfMethods/EfMethodsSource.cs index 81a8e6a..d4886f2 100644 --- a/src/BlueWest.MapTo/EfMethods/EfMethodsSource.cs +++ b/src/BlueWest.MapTo/EfMethods/EfMethodsSource.cs @@ -11,7 +11,13 @@ namespace MapTo.Sources { internal static class EfMethodsSource { - internal static SourceCode Generate(EfMethodsModel model, string addSourceTemplate, string updateSourceTemplate, string getOneBySourceTemplate) + internal static SourceCode Generate(EfMethodsModel model, + string addSourceTemplate, + string updateSourceTemplate, + string getOneBySourceTemplate, + string getOneWithSourceTemplate, + string getManyWithSourceTemplate + ) { using var builder = new SourceBuilder(); @@ -38,27 +44,38 @@ namespace MapTo.Sources foreach (var methodModel in model.MethodsModels.OrderBy(x => x.PropertyName)) { - if (methodModel is EfAddMethodsModel m) + switch (methodModel) { - builder - .EfAddAddEntityMethod(model,m, addSourceTemplate) + 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(); - continue; - } - - if (methodModel is EfUpdateMethodsModel updateModel) - { - builder - .EfAddUpdateEntityMethod(model, updateModel, updateSourceTemplate) + break; + case EfGetManyModel modl: + builder + .EfAddGetManyWithMethod(model, modl, getManyWithSourceTemplate) .WriteLine(); - continue; - } - if (methodModel is EfGetOneByModel getOneByModel) - { - builder - .EfAddGetOneEntityByMethod(model, getOneByModel, getOneBySourceTemplate) + break; + case EfGetOneWithModel modl: + builder + .EfAddGetOneEntityWithMethod(model, modl, getOneWithSourceTemplate) .WriteLine(); - continue; + break; + + + } diff --git a/src/BlueWest.MapTo/EfMethods/EfMethodsSource/EfGetOneWithTemplateSource.cs b/src/BlueWest.MapTo/EfMethods/EfMethodsSource/EfGetOneWithTemplateSource.cs new file mode 100644 index 0000000..29a1c00 --- /dev/null +++ b/src/BlueWest.MapTo/EfMethods/EfMethodsSource/EfGetOneWithTemplateSource.cs @@ -0,0 +1,107 @@ +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> 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 > where = null,") + .WriteLine($"Expression > 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; + } + } +} diff --git a/src/BlueWest.MapTo/MapToGenerator.cs b/src/BlueWest.MapTo/MapToGenerator.cs index aae2c2c..7aaa899 100644 --- a/src/BlueWest.MapTo/MapToGenerator.cs +++ b/src/BlueWest.MapTo/MapToGenerator.cs @@ -58,6 +58,7 @@ namespace MapTo foreach (var typeDeclarationSyntax in candidateTypes) { var mappingContext = MappingContext.Create(compilation, options, typeDeclarationSyntax); + mappingContext.Diagnostics.ForEach(context.ReportDiagnostic); if (mappingContext.Model is null) @@ -65,7 +66,6 @@ namespace MapTo continue; } - var (source, hintName) = typeDeclarationSyntax switch { StructDeclarationSyntax => MapStructSource.Generate(mappingContext.Model), diff --git a/src/BlueWest.MapTo/Models.cs b/src/BlueWest.MapTo/Models.cs index d5d3907..5963055 100644 --- a/src/BlueWest.MapTo/Models.cs +++ b/src/BlueWest.MapTo/Models.cs @@ -100,7 +100,7 @@ namespace MapTo internal class EfAddMethodsModel : EfEntityDataModel { public string CreateTypeFullName { get; set; } - public string CreateTypeIdentifierName { get; set; } + public string CreateTypeIdentifierName { get; set; } public string ReturnTypeFullName { get; set; } public string ReturnTypeIdentifierName { get; set; } @@ -137,6 +137,32 @@ namespace MapTo ByParamTypeName = returnTypeFullName; } } + + internal class EfGetOneWithModel : EfEntityDataModel + { + public string ReturnTypeIdentifierName { get; set; } + public string ReturnTypeFullName { get; set; } + + public EfGetOneWithModel(EfEntityDataModel entity, string returnTypeFullName, + string returnTypeIdentifierName) : base(entity.PropertyName, entity.EntityTypeFullName, entity.EntityTypeIdentifierName) + { + ReturnTypeIdentifierName = returnTypeIdentifierName; + ReturnTypeFullName = returnTypeFullName; + } + } + + internal class EfGetManyModel : EfEntityDataModel + { + public string ReturnTypeIdentifierName { get; set; } + public string ReturnTypeFullName { get; set; } + + public EfGetManyModel(EfEntityDataModel entity, string returnTypeFullName, + string returnTypeIdentifierName) : base(entity.PropertyName, entity.EntityTypeFullName, entity.EntityTypeIdentifierName) + { + ReturnTypeIdentifierName = returnTypeIdentifierName; + ReturnTypeFullName = returnTypeFullName; + } + } internal class EfUpdateMethodsModel : EfEntityDataModel