• 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 · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc