• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

loresoft / FluentCommand / 10891700765

16 Sep 2024 08:36PM UTC coverage: 54.514%. First build
10891700765

push

github

pwelter34
add GenerateReaderAttribute

1672 of 3548 branches covered (47.13%)

Branch coverage included in aggregate %.

37 of 131 new or added lines in 9 files covered. (28.24%)

4221 of 7262 relevant lines covered (58.12%)

229.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/FluentCommand.Generators/DataReaderFactoryGenerator.cs
1
using System.Collections.Immutable;
2

3
using FluentCommand.Generators.Models;
4

5
using Microsoft.CodeAnalysis;
6

7
namespace FluentCommand.Generators;
8

9
public abstract class DataReaderFactoryGenerator
10
{
11
    protected static void ReportDiagnostic(SourceProductionContext context, EquatableArray<Diagnostic> diagnostics)
12
    {
13
        foreach (var diagnostic in diagnostics)
×
14
            context.ReportDiagnostic(diagnostic);
×
15
    }
×
16

17
    protected static void WriteSource(SourceProductionContext context, EntityClass entityClass)
18
    {
19
        var qualifiedName = entityClass.EntityNamespace is null
×
20
            ? entityClass.EntityName
×
21
            : $"{entityClass.EntityNamespace}.{entityClass.EntityName}";
×
22

23
        var source = DataReaderFactoryWriter.Generate(entityClass);
×
24

25
        context.AddSource($"{qualifiedName}DataReaderExtensions.g.cs", source);
×
26
    }
×
27

28
    protected static EntityContext CreateContext(Location location, INamedTypeSymbol targetSymbol)
29
    {
NEW
30
        if (targetSymbol == null)
×
31
            return null;
×
32

NEW
33
        var fullyQualified = targetSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
×
34
        var classNamespace = targetSymbol.ContainingNamespace.ToDisplayString();
×
35
        var className = targetSymbol.Name;
×
36

37
        var mode = targetSymbol.Constructors.Any(c => c.Parameters.Length == 0)
×
38
            ? InitializationMode.ObjectInitializer
×
39
            : InitializationMode.Constructor;
×
40

41
        var propertySymbols = GetProperties(targetSymbol);
×
42

43
        if (mode == InitializationMode.ObjectInitializer)
×
44
        {
45
            var propertyArray = propertySymbols
×
NEW
46
                .Select(p => CreateProperty(p))
×
NEW
47
                .ToArray();
×
48

NEW
49
            var entity = new EntityClass(mode, fullyQualified, classNamespace, className, propertyArray);
×
NEW
50
            return new EntityContext(entity, []);
×
51
        }
52

53
        // constructor initialization
54
        var diagnostics = new List<Diagnostic>();
×
55

56
        // constructor with same number of parameters as properties
57
        var constructor = targetSymbol.Constructors.FirstOrDefault(c => c.Parameters.Length == propertySymbols.Count);
×
58
        if (constructor == null)
×
59
        {
60
            var constructorDiagnostic = Diagnostic.Create(
×
61
                DiagnosticDescriptors.InvalidConstructor,
×
NEW
62
                location,
×
63
                propertySymbols.Count,
×
64
                className
×
65
            );
×
66

67
            diagnostics.Add(constructorDiagnostic);
×
68

69
            return new EntityContext(null, diagnostics);
×
70
        }
71

72
        var properties = new List<EntityProperty>();
×
73
        foreach (var propertySymbol in propertySymbols)
×
74
        {
75
            // find matching constructor name
76
            var parameter = constructor
×
77
                .Parameters
×
78
                .FirstOrDefault(p => string.Equals(p.Name, propertySymbol.Name, StringComparison.InvariantCultureIgnoreCase));
×
79

80
            if (parameter == null)
×
81
            {
82
                var constructorDiagnostic = Diagnostic.Create(
×
83
                    DiagnosticDescriptors.InvalidConstructorParameter,
×
NEW
84
                    location,
×
85
                    propertySymbol.Name,
×
86
                    className
×
87
                );
×
88

89
                diagnostics.Add(constructorDiagnostic);
×
90

91
                continue;
×
92
            }
93

94
            var property = CreateProperty(propertySymbol, parameter.Name);
×
95
            properties.Add(property);
×
96
        }
97

NEW
98
        var entityClass = new EntityClass(mode, fullyQualified, classNamespace, className, properties);
×
99
        return new EntityContext(entityClass, diagnostics);
×
100
    }
101

102
    protected static List<IPropertySymbol> GetProperties(INamedTypeSymbol targetSymbol)
103
    {
104
        var properties = new Dictionary<string, IPropertySymbol>();
×
105

106
        var currentSymbol = targetSymbol;
×
107

108
        // get nested properties
109
        while (currentSymbol != null)
×
110
        {
111
            var propertySymbols = currentSymbol
×
112
                .GetMembers()
×
113
                .Where(m => m.Kind == SymbolKind.Property)
×
114
                .OfType<IPropertySymbol>()
×
115
                .Where(IsIncluded)
×
116
                .Where(p => !properties.ContainsKey(p.Name));
×
117

118
            foreach (var propertySymbol in propertySymbols)
×
119
                properties.Add(propertySymbol.Name, propertySymbol);
×
120

121
            currentSymbol = currentSymbol.BaseType;
×
122
        }
123

124
        return properties.Values.ToList();
×
125
    }
126

127
    protected static EntityProperty CreateProperty(IPropertySymbol propertySymbol, string parameterName = null)
128
    {
129
        var propertyType = propertySymbol.Type.ToDisplayString();
×
130
        var propertyName = propertySymbol.Name;
×
131

132
        // look for custom field converter
133
        var attributes = propertySymbol.GetAttributes();
×
134
        if (attributes == null || attributes.Length == 0)
×
135
        {
136
            return new EntityProperty(
×
137
                propertyName,
×
138
                propertyName,
×
139
                propertyType,
×
140
                parameterName);
×
141
        }
142

143
        var columnName = GetColumnName(attributes) ?? propertyName;
×
144

145
        var converter = attributes
×
146
            .FirstOrDefault(a => a.AttributeClass is
×
147
            {
×
148
                Name: "DataFieldConverterAttribute",
×
149
                ContainingNamespace.Name: "FluentCommand"
×
150
            });
×
151

152
        if (converter == null)
×
153
        {
154
            return new EntityProperty(
×
155
                propertyName,
×
156
                columnName,
×
157
                propertyType,
×
158
                parameterName);
×
159
        }
160

161
        // attribute contructor
162
        var converterType = converter.ConstructorArguments.FirstOrDefault();
×
163
        if (converterType.Value is INamedTypeSymbol converterSymbol)
×
164
        {
165
            return new EntityProperty(
×
166
                propertyName,
×
167
                columnName,
×
168
                propertyType,
×
169
                parameterName,
×
170
                converterSymbol.ToDisplayString());
×
171
        }
172

173
        // generic attribute
174
        var attributeClass = converter.AttributeClass;
×
175
        if (attributeClass is { IsGenericType: true }
×
176
            && attributeClass.TypeArguments.Length == attributeClass.TypeParameters.Length
×
177
            && attributeClass.TypeArguments.Length == 1)
×
178
        {
179
            var typeArgument = attributeClass.TypeArguments[0];
×
180
            var converterString = typeArgument.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
×
181

182
            return new EntityProperty(
×
183
                propertyName,
×
184
                columnName,
×
185
                propertyType,
×
186
                parameterName,
×
187
                converterString);
×
188
        }
189

190
        return new EntityProperty(
×
191
            propertyName,
×
192
            columnName,
×
193
            propertyType,
×
194
            parameterName);
×
195
    }
196

197
    protected static string GetColumnName(ImmutableArray<AttributeData> attributes)
198
    {
199
        var columnAttribute = attributes
×
200
           .FirstOrDefault(a => a.AttributeClass is
×
201
           {
×
202
               Name: "ColumnAttribute",
×
203
               ContainingNamespace:
×
204
               {
×
205
                   Name: "Schema",
×
206
                   ContainingNamespace:
×
207
                   {
×
208
                       Name: "DataAnnotations",
×
209
                       ContainingNamespace:
×
210
                       {
×
211
                           Name: "ComponentModel",
×
212
                           ContainingNamespace.Name: "System"
×
213
                       }
×
214
                   }
×
215
               }
×
216
           });
×
217

218
        if (columnAttribute == null)
×
219
            return null;
×
220

221
        // attribute contructor [Column("Name")]
222
        var converterType = columnAttribute.ConstructorArguments.FirstOrDefault();
×
223
        if (converterType.Value is string stringValue)
×
224
            return stringValue;
×
225

226
        return null;
×
227
    }
228

229
    protected static bool IsIncluded(IPropertySymbol propertySymbol)
230
    {
NEW
231
        var attributes = propertySymbol.GetAttributes();
×
NEW
232
        if (attributes.Length > 0 && attributes.Any(
×
NEW
233
                a => a.AttributeClass is
×
NEW
234
                {
×
NEW
235
                    Name: "NotMappedAttribute",
×
NEW
236
                    ContainingNamespace:
×
NEW
237
                    {
×
NEW
238
                        Name: "Schema",
×
NEW
239
                        ContainingNamespace:
×
NEW
240
                        {
×
NEW
241
                            Name: "DataAnnotations",
×
NEW
242
                            ContainingNamespace:
×
NEW
243
                            {
×
NEW
244
                                Name: "ComponentModel",
×
NEW
245
                                ContainingNamespace.Name: "System"
×
NEW
246
                            }
×
NEW
247
                        }
×
NEW
248
                    }
×
NEW
249
                }))
×
250
        {
NEW
251
            return false;
×
252
        }
253

NEW
254
        return !propertySymbol.IsIndexer && !propertySymbol.IsAbstract && propertySymbol.DeclaredAccessibility == Accessibility.Public;
×
255
    }
256
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc