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

loresoft / FluentCommand / 26618517770

29 May 2026 04:45AM UTC coverage: 55.778% (+0.03%) from 55.746%
26618517770

push

github

pwelter34
Handle nullable props and required JSON readers

1390 of 3261 branches covered (42.62%)

Branch coverage included in aggregate %.

47 of 54 new or added lines in 4 files covered. (87.04%)

1 existing line in 1 file now uncovered.

4455 of 7218 relevant lines covered (61.72%)

310.18 hits per line

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

69.71
/src/FluentCommand.Generators/DataReaderFactoryWriter.cs
1
using System.Text;
2

3
using FluentCommand.Generators.Models;
4

5
namespace FluentCommand.Generators;
6

7
public static class DataReaderFactoryWriter
8
{
9
    public static string Generate(EntityClass entityClass)
10
    {
11
        if (entityClass == null)
3 !
12
            throw new ArgumentNullException(nameof(entityClass));
×
13

14
        var codeBuilder = new IndentedStringBuilder();
3 ✔
15
        codeBuilder
3 ✔
16
            .AppendLine("// <auto-generated />")
3 ✔
17
            .AppendLine("#nullable enable")
3 ✔
18
            .AppendLine()
3 ✔
19
            .AppendLine("using global::FluentCommand.Extensions;")
3 ✔
20
            .AppendLine();
3 ✔
21

22
        codeBuilder
3 ✔
23
            .Append("namespace ")
3 ✔
24
            .AppendLine(entityClass.EntityNamespace)
3 ✔
25
            .AppendLine("{")
3 ✔
26
            .IncrementIndent();
3 ✔
27

28
        codeBuilder
3 ✔
29
            .AppendLine("/// <summary>")
3 ✔
30
            .AppendLine("/// Extension methods for FluentCommand")
3 ✔
31
            .AppendLine("/// </summary>")
3 ✔
32
            .Append("public static partial class ")
3 ✔
33
            .Append(entityClass.EntityName)
3 ✔
34
            .AppendLine("DataReaderExtensions")
3 ✔
35
            .AppendLine("{")
3 ✔
36
            .IncrementIndent();
3 ✔
37

38
        WriteQueryEntity(codeBuilder, entityClass);
3 ✔
39

40
        WriteQuerySingleEntity(codeBuilder, entityClass);
3 ✔
41

42
        WriteQueryEntityTask(codeBuilder, entityClass);
3 ✔
43

44
        WriteQuerySingleEntityTask(codeBuilder, entityClass);
3 ✔
45

46
        WriteEntityFactory(codeBuilder, entityClass);
3 ✔
47

48
        codeBuilder
3 ✔
49
            .DecrementIndent()
3 ✔
50
            .AppendLine("}") // class
3 ✔
51
            .DecrementIndent()
3 ✔
52
            .AppendLine("}"); // namespace
3 ✔
53

54
        return codeBuilder.ToString();
3 ✔
55
    }
56

57
    private static void WriteQuerySingleEntityTask(IndentedStringBuilder codeBuilder, EntityClass entity)
58
    {
59
        // public static Task<Entity> QuerySingleEntityAsync(this IDataQueryAsync dataQuery) => QuerySingleAsync(dataQuery, EntityFactory);
60
        codeBuilder
3 ✔
61
            .AppendLine("/// <summary>")
3 ✔
62
            .Append("/// Executes the query and returns the first row in the result as a <see cref=\"T:")
3 ✔
63
            .Append(entity.FullyQualified)
3 ✔
64
            .AppendLine("\"/> object.")
3 ✔
65
            .AppendLine("/// </summary>")
3 ✔
66
            .AppendLine("/// <param name=\"dataQuery\">The <see cref=\"T:FluentCommand.IDataQueryAsync\"/> for this extension method.</param>")
3 ✔
67
            .AppendLine("/// <param name=\"cancellationToken\">The cancellation instruction.</param>")
3 ✔
68
            .AppendLine("/// <returns>")
3 ✔
69
            .Append("/// A instance of <see cref=\"T:")
3 ✔
70
            .Append(entity.FullyQualified)
3 ✔
71
            .AppendLine("\"/>  if row exists; otherwise null.")
3 ✔
72
            .AppendLine("/// </returns>")
3 ✔
73
            .Append("[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"")
3 ✔
74
            .Append(ThisAssembly.Product)
3 ✔
75
            .Append("\", \"")
3 ✔
76
            .Append(ThisAssembly.InformationalVersion)
3 ✔
77
            .AppendLine("\")]")
3 ✔
78
            .Append("public static global::System.Threading.Tasks.Task<")
3 ✔
79
            .Append(entity.FullyQualified)
3 ✔
80
            .Append("?> QuerySingle")
3 ✔
81
            .AppendLine("Async<TEntity>(")
3 ✔
82
            .IncrementIndent()
3 ✔
83
            .AppendLine("this global::FluentCommand.IDataQueryAsync dataQuery,")
3 ✔
84
            .AppendLine("global::System.Threading.CancellationToken cancellationToken = default)")
3 ✔
85
            .Append("where TEntity : ")
3 ✔
86
            .AppendLine(entity.FullyQualified)
3 ✔
87
            .DecrementIndent()
3 ✔
88
            .AppendLine("{")
3 ✔
89
            .IncrementIndent()
3 ✔
90
            .Append("return dataQuery.QuerySingleAsync<")
3 ✔
91
            .Append(entity.FullyQualified)
3 ✔
92
            .AppendLine(">(")
3 ✔
93
            .IncrementIndent()
3 ✔
94
            .Append("factory: ")
3 ✔
95
            .Append(entity.EntityName)
3 ✔
96
            .Append("DataReaderExtensions.")
3 ✔
97
            .Append(entity.EntityName)
3 ✔
98
            .AppendLine("Factory,")
3 ✔
99
            .AppendLine("commandBehavior: global::System.Data.CommandBehavior.SequentialAccess |")
3 ✔
100
            .AppendLine("                 global::System.Data.CommandBehavior.SingleResult |")
3 ✔
101
            .AppendLine("                 global::System.Data.CommandBehavior.SingleRow,")
3 ✔
102
            .AppendLine("cancellationToken: cancellationToken);")
3 ✔
103
            .DecrementIndent()
3 ✔
104
            .DecrementIndent()
3 ✔
105
            .AppendLine("}")
3 ✔
106
            .AppendLine();
3 ✔
107
    }
3 ✔
108

109
    private static void WriteQueryEntityTask(IndentedStringBuilder codeBuilder, EntityClass entity)
110
    {
111
        // public static Task<IEnumerable<Entity>> QueryEntityAsync(this IDataQueryAsync dataQuery) => QueryAsync(dataQuery, EntityFactory);
112
        codeBuilder
3 ✔
113
            .AppendLine("/// <summary>")
3 ✔
114
            .Append("/// Executes the command against the connection and converts the results to <see cref=\"T:")
3 ✔
115
            .Append(entity.FullyQualified)
3 ✔
116
            .AppendLine("\"/> objects.")
3 ✔
117
            .AppendLine("/// </summary>")
3 ✔
118
            .AppendLine("/// <param name=\"dataQuery\">The <see cref=\"T:FluentCommand.IDataQueryAsync\"/> for this extension method.</param>")
3 ✔
119
            .AppendLine("/// <param name=\"cancellationToken\">The cancellation instruction.</param>")
3 ✔
120
            .AppendLine("/// <returns>")
3 ✔
121
            .Append("/// An <see cref=\"T:System.Collections.Generic.IEnumerable`1\" /> of <see cref=\"T:")
3 ✔
122
            .Append(entity.FullyQualified)
3 ✔
123
            .AppendLine("\"/> objects.")
3 ✔
124
            .AppendLine("/// </returns>")
3 ✔
125
            .Append("[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"")
3 ✔
126
            .Append(ThisAssembly.Product)
3 ✔
127
            .Append("\", \"")
3 ✔
128
            .Append(ThisAssembly.InformationalVersion)
3 ✔
129
            .AppendLine("\")]")
3 ✔
130
            .Append("public static global::System.Threading.Tasks.Task<global::System.Collections.Generic.IEnumerable<")
3 ✔
131
            .Append(entity.FullyQualified)
3 ✔
132
            .AppendLine(">> QueryAsync<TEntity>(")
3 ✔
133
            .IncrementIndent()
3 ✔
134
            .AppendLine("this global::FluentCommand.IDataQueryAsync dataQuery,")
3 ✔
135
            .AppendLine("global::System.Threading.CancellationToken cancellationToken = default)")
3 ✔
136
            .Append("where TEntity : ")
3 ✔
137
            .AppendLine(entity.FullyQualified)
3 ✔
138
            .DecrementIndent()
3 ✔
139
            .AppendLine("{")
3 ✔
140
            .IncrementIndent()
3 ✔
141
            .Append("return dataQuery.QueryAsync<")
3 ✔
142
            .Append(entity.FullyQualified)
3 ✔
143
            .AppendLine(">(")
3 ✔
144
            .IncrementIndent()
3 ✔
145
            .Append("factory: ")
3 ✔
146
            .Append(entity.EntityName)
3 ✔
147
            .Append("DataReaderExtensions.")
3 ✔
148
            .Append(entity.EntityName)
3 ✔
149
            .AppendLine("Factory,")
3 ✔
150
            .AppendLine("commandBehavior: global::System.Data.CommandBehavior.SequentialAccess |")
3 ✔
151
            .AppendLine("                 global::System.Data.CommandBehavior.SingleResult,")
3 ✔
152
            .AppendLine("cancellationToken: cancellationToken);")
3 ✔
153
            .DecrementIndent()
3 ✔
154
            .DecrementIndent()
3 ✔
155
            .AppendLine("}")
3 ✔
156
            .AppendLine();
3 ✔
157
    }
3 ✔
158

159
    private static void WriteQuerySingleEntity(IndentedStringBuilder codeBuilder, EntityClass entity)
160
    {
161
        // public static Entity QuerySingleEntity(this IDataQuery dataQuery) => QuerySingle(dataQuery, EntityFactory);
162
        codeBuilder
3 ✔
163
            .AppendLine("/// <summary>")
3 ✔
164
            .Append("/// Executes the query and returns the first row in the result as a <see cref=\"T:")
3 ✔
165
            .Append(entity.FullyQualified)
3 ✔
166
            .AppendLine("\"/> object.")
3 ✔
167
            .AppendLine("/// </summary>")
3 ✔
168
            .AppendLine("/// <param name=\"dataQuery\">The <see cref=\"T:FluentCommand.IDataQuery\"/> for this extension method.</param>")
3 ✔
169
            .AppendLine("/// <returns>")
3 ✔
170
            .Append("/// A instance of <see cref=\"T:")
3 ✔
171
            .Append(entity.FullyQualified)
3 ✔
172
            .AppendLine("\"/>  if row exists; otherwise null.")
3 ✔
173
            .AppendLine("/// </returns>")
3 ✔
174
            .Append("[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"")
3 ✔
175
            .Append(ThisAssembly.Product)
3 ✔
176
            .Append("\", \"")
3 ✔
177
            .Append(ThisAssembly.InformationalVersion)
3 ✔
178
            .AppendLine("\")]")
3 ✔
179
            .Append("public static ")
3 ✔
180
            .Append(entity.FullyQualified)
3 ✔
181
            .AppendLine("? QuerySingle<TEntity>(")
3 ✔
182
            .IncrementIndent()
3 ✔
183
            .AppendLine("this global::FluentCommand.IDataQuery dataQuery)")
3 ✔
184
            .Append("where TEntity : ")
3 ✔
185
            .AppendLine(entity.FullyQualified)
3 ✔
186
            .DecrementIndent()
3 ✔
187
            .AppendLine("{")
3 ✔
188
            .IncrementIndent()
3 ✔
189
            .Append("return dataQuery.QuerySingle<")
3 ✔
190
            .Append(entity.FullyQualified)
3 ✔
191
            .AppendLine(">(")
3 ✔
192
            .IncrementIndent()
3 ✔
193
            .Append("factory: ")
3 ✔
194
            .Append(entity.EntityName)
3 ✔
195
            .Append("DataReaderExtensions.")
3 ✔
196
            .Append(entity.EntityName)
3 ✔
197
            .AppendLine("Factory,")
3 ✔
198
            .AppendLine("commandBehavior: global::System.Data.CommandBehavior.SequentialAccess |")
3 ✔
199
            .AppendLine("                 global::System.Data.CommandBehavior.SingleResult |")
3 ✔
200
            .AppendLine("                 global::System.Data.CommandBehavior.SingleRow);")
3 ✔
201
            .DecrementIndent()
3 ✔
202
            .DecrementIndent()
3 ✔
203
            .AppendLine("}")
3 ✔
204
            .AppendLine();
3 ✔
205
    }
3 ✔
206

207
    private static void WriteQueryEntity(IndentedStringBuilder codeBuilder, EntityClass entity)
208
    {
209
        // public static IEnumerable<Entity> QueryEntity(this IDataQuery dataQuery) => Query(dataQuery, EntityFactory);
210
        codeBuilder
3 ✔
211
            .AppendLine("/// <summary>")
3 ✔
212
            .Append("/// Executes the command against the connection and converts the results to <see cref=\"T:")
3 ✔
213
            .Append(entity.FullyQualified)
3 ✔
214
            .AppendLine("\"/> objects.")
3 ✔
215
            .AppendLine("/// </summary>")
3 ✔
216
            .AppendLine("/// <param name=\"dataQuery\">The <see cref=\"T:FluentCommand.IDataQuery\"/> for this extension method.</param>")
3 ✔
217
            .AppendLine("/// <returns>")
3 ✔
218
            .Append("/// An <see cref=\"T:System.Collections.Generic.IEnumerable`1\" /> of <see cref=\"T:")
3 ✔
219
            .Append(entity.FullyQualified)
3 ✔
220
            .AppendLine("\"/> objects.")
3 ✔
221
            .AppendLine("/// </returns>")
3 ✔
222
            .Append("[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"")
3 ✔
223
            .Append(ThisAssembly.Product)
3 ✔
224
            .Append("\", \"")
3 ✔
225
            .Append(ThisAssembly.InformationalVersion)
3 ✔
226
            .AppendLine("\")]")
3 ✔
227
            .Append("public static global::System.Collections.Generic.IEnumerable<")
3 ✔
228
            .Append(entity.FullyQualified)
3 ✔
229
            .AppendLine("> Query<TEntity>(")
3 ✔
230
            .IncrementIndent()
3 ✔
231
            .AppendLine("this global::FluentCommand.IDataQuery dataQuery)")
3 ✔
232
            .Append("where TEntity : ")
3 ✔
233
            .AppendLine(entity.FullyQualified)
3 ✔
234
            .DecrementIndent()
3 ✔
235
            .AppendLine("{")
3 ✔
236
            .IncrementIndent()
3 ✔
237
            .Append("return dataQuery.Query<")
3 ✔
238
            .Append(entity.FullyQualified)
3 ✔
239
            .AppendLine(">(")
3 ✔
240
            .IncrementIndent()
3 ✔
241
            .Append("factory: ")
3 ✔
242
            .Append(entity.EntityName)
3 ✔
243
            .Append("DataReaderExtensions.")
3 ✔
244
            .Append(entity.EntityName)
3 ✔
245
            .AppendLine("Factory,")
3 ✔
246
            .AppendLine("commandBehavior: global::System.Data.CommandBehavior.SequentialAccess |")
3 ✔
247
            .AppendLine("                 global::System.Data.CommandBehavior.SingleResult);")
3 ✔
248
            .DecrementIndent()
3 ✔
249
            .DecrementIndent()
3 ✔
250
            .AppendLine("}")
3 ✔
251
            .AppendLine();
3 ✔
252
    }
3 ✔
253

254
    private static void WriteEntityFactory(IndentedStringBuilder codeBuilder, EntityClass entity)
255
    {
256
        codeBuilder
3 ✔
257
            .AppendLine("/// <summary>")
3 ✔
258
            .Append("/// A factory for creating <see cref=\"T:")
3 ✔
259
            .Append(entity.FullyQualified)
3 ✔
260
            .AppendLine("\"/> objects from the current row in the specified <paramref name=\"dataRecord\"/>.")
3 ✔
261
            .AppendLine("/// </summary>")
3 ✔
262
            .AppendLine("/// <param name=\"dataRecord\">The open <see cref=\"T:System.Data.IDataReader\"/> to get the object from.</param>")
3 ✔
263
            .AppendLine("/// <returns>")
3 ✔
264
            .Append("/// A instance of <see cref=\"")
3 ✔
265
            .Append(entity.FullyQualified)
3 ✔
266
            .AppendLine("\"/>  having property names set that match the field names in the <paramref name=\"dataRecord\"/>.")
3 ✔
267
            .AppendLine("/// </returns>")
3 ✔
268
            .Append("[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"")
3 ✔
269
            .Append(ThisAssembly.Product)
3 ✔
270
            .Append("\", \"")
3 ✔
271
            .Append(ThisAssembly.InformationalVersion)
3 ✔
272
            .AppendLine("\")]")
3 ✔
273
            .Append("public static ")
3 ✔
274
            .Append(entity.FullyQualified)
3 ✔
275
            .Append(" ")
3 ✔
276
            .Append(entity.EntityName)
3 ✔
277
            .AppendLine("Factory(this global::System.Data.IDataReader dataRecord)")
3 ✔
278
            .AppendLine("{")
3 ✔
279
            .IncrementIndent()
3 ✔
280
            .AppendLine("if (dataRecord == null)")
3 ✔
281
            .IncrementIndent()
3 ✔
282
            .AppendLine("throw new global::System.ArgumentNullException(nameof(dataRecord));")
3 ✔
283
            .DecrementIndent()
3 ✔
284
            .AppendLine();
3 ✔
285

286
        foreach (var entityProperty in entity.Properties)
30 ✔
287
        {
288
            if (entityProperty.IsNotMapped)
12 !
289
                continue;
290

291
            var aliasType = GetAliasMap(entityProperty.PropertyType);
12 ✔
292
            var fieldName = CamelCase(entityProperty.PropertyName);
12 ✔
293

294
            // local variable
295
            codeBuilder
12 ✔
296
                .Append(aliasType)
12 ✔
297
                .Append(" v_")
12 ✔
298
                .Append(fieldName)
12 ✔
299
                .Append(" = default")
12 ✔
300
                .AppendIf("!", _ => !entityProperty.IsNullable)
12 ✔
301
                .AppendLine(";");
12 ✔
302
        }
303

304
        codeBuilder
3 ✔
305
            .AppendLine()
3 ✔
306
            .AppendLine("for (var __index = 0; __index < dataRecord.FieldCount; __index++)")
3 ✔
307
            .AppendLine("{")
3 ✔
308
            .IncrementIndent()
3 ✔
309
            .AppendLine("if (dataRecord.IsDBNull(__index))")
3 ✔
310
            .IncrementIndent()
3 ✔
311
            .AppendLine(" continue;")
3 ✔
312
            .DecrementIndent()
3 ✔
313
            .AppendLine();
3 ✔
314

315
        codeBuilder
3 ✔
316
            .AppendLine("var __name = dataRecord.GetName(__index);")
3 ✔
317
            .AppendLine("switch (__name)")
3 ✔
318
            .AppendLine("{")
3 ✔
319
            .IncrementIndent();
3 ✔
320

321
        foreach (var entityProperty in entity.Properties)
30 ✔
322
        {
323
            if (entityProperty.IsNotMapped)
12 !
324
                continue;
325

326
            var fieldName = CamelCase(entityProperty.PropertyName);
12 ✔
327

328
            codeBuilder
12 ✔
329
                .Append("case \"")
12 ✔
330
                .Append(entityProperty.ColumnName)
12 ✔
331
                .AppendLine("\":");
12 ✔
332

333
            if (entityProperty.IsJsonColumn)
12 ✔
334
            {
335
                var jsonReaderName = entityProperty.IsNullable
4 ✔
336
                    ? "GetFromJson"
4 ✔
337
                    : "GetRequiredFromJson";
4 ✔
338

339
                codeBuilder
4 ✔
340
                    .IncrementIndent()
4 ✔
341
                    .Append("v_")
4 ✔
342
                    .Append(fieldName)
4 ✔
343
                    .Append(" = dataRecord.")
4 ✔
344
                    .Append(jsonReaderName)
4 ✔
345
                    .Append("<")
4 ✔
346
                    .Append(entityProperty.PropertyType)
4 ✔
347
                    .Append(">(__index")
4 ✔
348
                    .Append(GetJsonReaderArgument(entityProperty))
4 ✔
349
                    .AppendLine(");")
4 ✔
350
                    .AppendLine("break;")
4 ✔
351
                    .DecrementIndent();
4 ✔
352
            }
353
            else if (entityProperty.IsEnum)
8 ✔
354
            {
355
                WriteEnumColumnReader(codeBuilder, entityProperty, fieldName);
2 ✔
356
            }
357
            else if (string.IsNullOrEmpty(entityProperty.ConverterName))
6 !
358
            {
359
                var readerName = GetReaderName(entityProperty);
6 ✔
360

361
                codeBuilder
6 ✔
362
                    .IncrementIndent()
6 ✔
363
                    .Append("v_")
6 ✔
364
                    .Append(fieldName)
6 ✔
365
                    .Append(" = dataRecord.")
6 ✔
366
                    .Append(readerName)
6 ✔
367
                    .AppendLine("(__index);")
6 ✔
368
                    .AppendLine("break;")
6 ✔
369
                    .DecrementIndent();
6 ✔
370
            }
371
            else
372
            {
373
                // create converter via singleton helper
374
                codeBuilder
×
375
                    .IncrementIndent()
×
376
                    .Append("var c_")
×
377
                    .Append(fieldName)
×
378
                    .Append(" = global::FluentCommand.Internal.Singleton<")
×
379
                    .Append(entityProperty.ConverterName!)
×
380
                    .AppendLine(">.Current")
×
381
                    .IncrementIndent()
×
382
                    .Append("as global::FluentCommand.IDataFieldConverter<")
×
383
                    .Append(entityProperty.PropertyType)
×
384
                    .AppendLine(">;")
×
385
                    .DecrementIndent()
×
386
                    .AppendLine();
×
387

388
                // read via converter instance
389
                codeBuilder
×
390
                    .Append("v_")
×
391
                    .Append(fieldName)
×
392
                    .Append(" = c_")
×
393
                    .Append(fieldName)
×
394
                    .AppendLine(".ReadValue(dataRecord, __index);")
×
395
                    .AppendLine("break;")
×
396
                    .DecrementIndent();
×
397
            }
398
        }
399

400
        codeBuilder
3 ✔
401
            .DecrementIndent()
3 ✔
402
            .AppendLine("}") // switch
3 ✔
403
            .DecrementIndent()
3 ✔
404
            .AppendLine("}") // for
3 ✔
405
            .AppendLine();
3 ✔
406

407
        if (entity.InitializationMode == InitializationMode.Constructor)
3 !
408
            WriteReturnConstructor(codeBuilder, entity);
×
409
        else
410
            WriteReturnObjectInitializer(codeBuilder, entity);
3 ✔
411

412
        codeBuilder
3 ✔
413
            .DecrementIndent()
3 ✔
414
            .AppendLine("}") // method
3 ✔
415
            .AppendLine();
3 ✔
416
    }
3 ✔
417

418
    private static void WriteEnumColumnReader(IndentedStringBuilder codeBuilder, EntityProperty entityProperty, string fieldName)
419
    {
420
        codeBuilder
2 ✔
421
            .IncrementIndent()
2 ✔
422
            .Append("v_")
2 ✔
423
            .Append(fieldName)
2 ✔
424
            .Append(" = ")
2 ✔
425
            .Append(GetEnumReadExpression(entityProperty))
2 ✔
426
            .AppendLine(";")
2 ✔
427
            .AppendLine("break;")
2 ✔
428
            .DecrementIndent();
2 ✔
429
    }
2 ✔
430

431
    private static string GetEnumReadExpression(EntityProperty entityProperty)
432
    {
433
        var underlyingType = entityProperty.EnumUnderlyingType ?? "int";
2 !
434

435
        if (entityProperty.IsNullableEnum)
2 ✔
436
            return $"({entityProperty.PropertyType})dataRecord.GetValue<{underlyingType}?>(__index)";
1 ✔
437

438
        return $"({entityProperty.PropertyType})dataRecord.{GetReaderName(underlyingType)}(__index)";
1 ✔
439
    }
440

441
    private static void WriteReturnConstructor(IndentedStringBuilder codeBuilder, EntityClass entity)
442
    {
443
        codeBuilder
×
444
            .Append("return new ")
×
445
            .Append(entity.FullyQualified)
×
446
            .AppendLine("(")
×
447
            .IncrementIndent();
×
448

449
        var mappedProperties = entity.Properties.Where(p => !p.IsNotMapped).ToList();
×
450
        var index = 0;
×
451
        var count = mappedProperties.Count;
×
452

453
        foreach (var entityProperty in mappedProperties)
×
454
        {
455
            var fieldName = CamelCase(entityProperty.PropertyName);
×
456
            codeBuilder
×
457
                .Append(entityProperty.ParameterName!)
×
458
                .Append(": ")
×
459
                .Append(" v_")
×
460
                .Append(fieldName);
×
461

462
            if (++index == count)
×
463
                codeBuilder.AppendLine();
×
464
            else
465
                codeBuilder.AppendLine(",");
×
466
        }
467

468
        codeBuilder
×
469
            .DecrementIndent()
×
470
            .AppendLine(");"); // new
×
471
    }
×
472

473
    private static void WriteReturnObjectInitializer(IndentedStringBuilder codeBuilder, EntityClass entity)
474
    {
475
        codeBuilder
3 ✔
476
            .Append("return new ")
3 ✔
477
            .AppendLine(entity.FullyQualified)
3 ✔
478
            .AppendLine("{")
3 ✔
479
            .IncrementIndent();
3 ✔
480

481
        var mappedProperties = entity.Properties.Where(p => !p.IsNotMapped).ToList();
3 ✔
482
        var index = 0;
3 ✔
483
        var count = mappedProperties.Count;
3 ✔
484

485
        foreach (var entityProperty in mappedProperties)
30 ✔
486
        {
487
            var fieldName = CamelCase(entityProperty.PropertyName);
12 ✔
488
            codeBuilder
12 ✔
489
                .Append(entityProperty.PropertyName)
12 ✔
490
                .Append(" = ")
12 ✔
491
                .Append(" v_")
12 ✔
492
                .Append(fieldName);
12 ✔
493

494
            if (++index == count)
12 ✔
495
                codeBuilder.AppendLine();
3 ✔
496
            else
497
                codeBuilder.AppendLine(",");
9 ✔
498
        }
499

500
        codeBuilder
3 ✔
501
            .DecrementIndent()
3 ✔
502
            .AppendLine("};"); // new
3 ✔
503
    }
3 ✔
504

505
    private static string GetAliasMap(string type)
506
    {
507
        return type switch
12 !
508
        {
12 ✔
509
            "System.Boolean" => "bool",
1 ✔
510
            "System.Byte" => "byte",
×
511
            "System.Byte[]" => "byte[]",
1 ✔
512
            "System.Char" => "char",
×
513
            "System.Decimal" => "decimal",
×
514
            "System.Double" => "double",
×
515
            "System.Single" => "float",
×
516
            "System.Int16" => "short",
×
517
            "System.Int32" => "int",
1 ✔
518
            "System.Int64" => "long",
×
519
            "System.String" => "string",
1 ✔
520
            _ => type,
8 ✔
521
        };
12 ✔
522
    }
523

524
    private static string GetReaderName(EntityProperty entityProperty)
525
    {
526
        var propertyType = entityProperty.IsNullable
6 !
527
            ? entityProperty.PropertyType.Substring(0, entityProperty.PropertyType.Length - 1)
6 ✔
528
            : entityProperty.PropertyType;
6 ✔
529

530
        return GetReaderName(propertyType);
6 ✔
531
    }
532

533
    private static string GetReaderName(string propertyType)
534
    {
535
        return propertyType switch
7 !
536
        {
7 ✔
537
            "System.Boolean" => "GetBoolean",
1 ✔
538
            "System.Byte" => "GetByte",
×
539
            "System.Byte[]" => "GetBytes",
1 ✔
540
            "System.Char" => "GetChar",
×
541
            "System.DateTime" => "GetDateTime",
×
542
            "System.DateTimeOffset" => "GetDateTimeOffset",
1 ✔
543
            "System.Decimal" => "GetDecimal",
×
544
            "System.Double" => "GetDouble",
×
545
            "System.Guid" => "GetGuid",
×
546
            "System.Single" => "GetFloat",
×
547
            "System.Int16" => "GetInt16",
×
548
            "System.Int32" => "GetInt32",
1 ✔
549
            "System.Int64" => "GetInt64",
×
550
            "System.String" => "GetString",
1 ✔
551
            "bool" => "GetBoolean",
×
552
            "byte" => "GetByte",
×
553
            "byte[]" => "GetBytes",
×
554
            "char" => "GetChar",
×
555
            "decimal" => "GetDecimal",
×
556
            "double" => "GetDouble",
×
557
            "float" => "GetFloat",
×
558
            "short" => "GetInt16",
1 ✔
559
            "int" => "GetInt32",
1 ✔
560
            "long" => "GetInt64",
×
561
            "string" => "GetString",
×
562
            "FluentCommand.ConcurrencyToken" => "GetBytes",
×
NEW
563
            _ => $"GetValue<{propertyType}>"
×
564
        };
7 ✔
565
    }
566

567
    private static string GetJsonReaderArgument(EntityProperty entityProperty)
568
    {
569
        if (!string.IsNullOrEmpty(entityProperty.JsonOptionsProviderName))
4 ✔
570
            return $", {entityProperty.JsonOptionsProviderName}.Options";
1 ✔
571

572
        if (!string.IsNullOrEmpty(entityProperty.JsonContextName)
3 ✔
573
            && !string.IsNullOrEmpty(entityProperty.JsonTypeInfoPropertyName))
3 ✔
574
        {
575
            return $", {entityProperty.JsonContextName}.Default.{entityProperty.JsonTypeInfoPropertyName}";
1 ✔
576
        }
577

578
        return string.Empty;
2 ✔
579
    }
580

581
    private static string CamelCase(string name)
582
    {
583
        if (string.IsNullOrEmpty(name) || !char.IsUpper(name[0]))
36 !
584
            return name;
×
585

586
        char[] chars = name.ToCharArray();
36 ✔
587
        FixCasing(chars);
36 ✔
588

589
        return new string(chars);
36 ✔
590
    }
591

592
    private static void FixCasing(Span<char> chars)
593
    {
594
        for (int i = 0; i < chars.Length; i++)
144 ✔
595
        {
596
            if (i == 1 && !char.IsUpper(chars[i]))
72 ✔
597
                break;
598

599
            bool hasNext = (i + 1 < chars.Length);
36 ✔
600

601
            // Stop when next char is already lowercase.
602
            if (i > 0 && hasNext && !char.IsUpper(chars[i + 1]))
36 !
603
            {
604
                // If the next char is a space, lowercase current char before exiting.
605
                if (chars[i + 1] == ' ')
×
606
                    chars[i] = char.ToLowerInvariant(chars[i]);
×
607

608
                break;
×
609
            }
610

611
            chars[i] = char.ToLowerInvariant(chars[i]);
36 ✔
612
        }
613
    }
36 ✔
614
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc