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

loresoft / FluentCommand / 22970781217

11 Mar 2026 07:32PM UTC coverage: 56.585% (+0.2%) from 56.372%
22970781217

push

github

pwelter34
Add ParameterJson overloads

1277 of 2823 branches covered (45.24%)

Branch coverage included in aggregate %.

0 of 4 new or added lines in 1 file covered. (0.0%)

64 existing lines in 4 files now uncovered.

3892 of 6312 relevant lines covered (61.66%)

367.61 hits per line

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

68.18
/src/FluentCommand/DataConfigurationBuilder.cs
1
using System.Data.Common;
2

3
using FluentCommand.Extensions;
4
using FluentCommand.Query.Generators;
5

6
using Microsoft.Extensions.Configuration;
7
using Microsoft.Extensions.DependencyInjection;
8
using Microsoft.Extensions.DependencyInjection.Extensions;
9

10
namespace FluentCommand;
11

12
/// <summary>
13
/// A configuration builder class
14
/// </summary>
15
public class DataConfigurationBuilder
16
{
17
    private readonly IServiceCollection _services;
18
    private string _nameOrConnectionString;
19
    private Type _providerFactoryType;
20
    private Type _dataCacheType;
21
    private Type _queryGeneratorType;
22
    private Type _queryLoggerType;
23

24
    /// <summary>
25
    /// Initializes a new instance of the <see cref="DataConfigurationBuilder"/> class.
26
    /// </summary>
27
    /// <param name="services">The services.</param>
28
    public DataConfigurationBuilder(IServiceCollection services)
4✔
29
    {
30
        _services = services;
4✔
31
    }
4✔
32

33

34
    /// <summary>
35
    /// Set the connection string or the name of connection string located in the application configuration
36
    /// </summary>
37
    /// <param name="nameOrConnectionString">The connection string or the name of connection string located in the application configuration.</param>
38
    /// <returns>
39
    /// The same configuration builder so that multiple calls can be chained.
40
    /// </returns>
41
    public DataConfigurationBuilder UseConnectionName(string nameOrConnectionString)
42
    {
43
        _nameOrConnectionString = nameOrConnectionString;
1✔
44
        return this;
1✔
45
    }
46

47
    /// <summary>
48
    /// The connection string to use with fluent command.
49
    /// </summary>
50
    /// <param name="connectionString">The connection string.</param>
51
    /// <returns>
52
    /// The same configuration builder so that multiple calls can be chained.
53
    /// </returns>
54
    public DataConfigurationBuilder UseConnectionString(string connectionString)
55
    {
56
        _nameOrConnectionString = connectionString;
3✔
57
        return this;
3✔
58
    }
59

60

61
    /// <summary>
62
    /// Adds the provider factory to use with this configuration.
63
    /// </summary>
64
    /// <typeparam name="TService">The type of the service.</typeparam>
65
    /// <param name="providerFactory">The provider factory.</param>
66
    /// <returns>
67
    /// The same configuration builder so that multiple calls can be chained.
68
    /// </returns>
69
    /// <seealso cref="DbProviderFactory"/>
70
    public DataConfigurationBuilder AddProviderFactory<TService>(TService providerFactory)
71
        where TService : DbProviderFactory
72
    {
73
        _providerFactoryType = typeof(TService);
4✔
74
        _services.TryAddSingleton(providerFactory);
4✔
75
        return this;
4✔
76
    }
77

78
    /// <summary>
79
    /// Adds the provider factory to use with this configuration.
80
    /// </summary>
81
    /// <typeparam name="TService">The type of the service.</typeparam>
82
    /// <param name="implementationFactory">The implementation factory.</param>
83
    /// <returns>
84
    /// The same configuration builder so that multiple calls can be chained.
85
    /// </returns>
86
    /// <seealso cref="DbProviderFactory"/>
87
    public DataConfigurationBuilder AddProviderFactory<TService>(Func<IServiceProvider, TService> implementationFactory)
88
        where TService : DbProviderFactory
89
    {
90
        _providerFactoryType = typeof(TService);
×
91
        _services.TryAddSingleton(implementationFactory);
×
92
        return this;
×
93
    }
94

95
    /// <summary>
96
    /// Adds the provider factory to use with this configuration.
97
    /// </summary>
98
    /// <typeparam name="TService">The type of the service.</typeparam>
99
    /// <returns>
100
    /// The same configuration builder so that multiple calls can be chained.
101
    /// </returns>
102
    /// <seealso cref="DbProviderFactory"/>
103
    public DataConfigurationBuilder AddProviderFactory<TService>()
104
        where TService : DbProviderFactory
105
    {
106
        _providerFactoryType = typeof(TService);
×
107
        _services.TryAddSingleton<TService>();
×
108
        return this;
×
109
    }
110

111

112
    /// <summary>
113
    /// Adds the data cache service to use with this configuration.
114
    /// </summary>
115
    /// <typeparam name="TService">The type of the service.</typeparam>
116
    /// <param name="dataCache">The data cache.</param>
117
    /// <returns>
118
    /// The same configuration builder so that multiple calls can be chained.
119
    /// </returns>
120
    /// <seealso cref="IDataCache"/>
121
    public DataConfigurationBuilder AddDataCache<TService>(TService dataCache)
122
        where TService : class, IDataCache
123
    {
124
        _dataCacheType = typeof(TService);
×
125
        _services.TryAddSingleton(dataCache);
×
126
        return this;
×
127
    }
128

129
    /// <summary>
130
    /// Adds the data cache service to use with this configuration.
131
    /// </summary>
132
    /// <typeparam name="TService">The type of the service.</typeparam>
133
    /// <param name="implementationFactory">The implementation factory.</param>
134
    /// <returns>
135
    /// The same configuration builder so that multiple calls can be chained.
136
    /// </returns>
137
    /// <seealso cref="IDataCache"/>
138
    public DataConfigurationBuilder AddDataCache<TService>(Func<IServiceProvider, TService> implementationFactory)
139
        where TService : class, IDataCache
140
    {
141
        _dataCacheType = typeof(TService);
×
142
        _services.TryAddSingleton(implementationFactory);
×
143
        return this;
×
144
    }
145

146
    /// <summary>
147
    /// Adds the data cache service to use with this configuration.
148
    /// </summary>
149
    /// <typeparam name="TService">The type of the service.</typeparam>
150
    /// <returns>
151
    /// The same configuration builder so that multiple calls can be chained.
152
    /// </returns>
153
    /// <seealso cref="IDataCache"/>
154
    public DataConfigurationBuilder AddDataCache<TService>()
155
        where TService : class, IDataCache
156
    {
157
        _dataCacheType = typeof(TService);
2✔
158
        _services.TryAddSingleton<TService>();
2✔
159
        return this;
2✔
160
    }
161

162

163
    /// <summary>
164
    /// Adds the query generator service to use with this configuration.
165
    /// </summary>
166
    /// <typeparam name="TService">The type of the service.</typeparam>
167
    /// <param name="queryGenerator">The query generator.</param>
168
    /// <returns>
169
    /// The same configuration builder so that multiple calls can be chained.
170
    /// </returns>
171
    /// <seealso cref="IQueryGenerator"/>
172
    public DataConfigurationBuilder AddQueryGenerator<TService>(TService queryGenerator)
173
        where TService : class, IQueryGenerator
174
    {
175
        _queryGeneratorType = typeof(TService);
×
176
        _services.TryAddSingleton(queryGenerator);
×
177
        return this;
×
178
    }
179

180
    /// <summary>
181
    /// Adds the query generator service to use with this configuration.
182
    /// </summary>
183
    /// <typeparam name="TService">The type of the service.</typeparam>
184
    /// <returns>
185
    /// The same configuration builder so that multiple calls can be chained.
186
    /// </returns>
187
    /// <seealso cref="IQueryGenerator"/>
188
    public DataConfigurationBuilder AddQueryGenerator<TService>()
189
        where TService : class, IQueryGenerator
190
    {
191
        _queryGeneratorType = typeof(TService);
4✔
192
        _services.TryAddSingleton<TService>();
4✔
193
        return this;
4✔
194
    }
195

196
    /// <summary>
197
    /// Adds the query generator service to use with this configuration.
198
    /// </summary>
199
    /// <typeparam name="TService">The type of the service.</typeparam>
200
    /// <param name="implementationFactory">The implementation factory.</param>
201
    /// <returns>
202
    /// The same configuration builder so that multiple calls can be chained.
203
    /// </returns>
204
    /// <seealso cref="IQueryGenerator"/>
205
    public DataConfigurationBuilder AddQueryGenerator<TService>(Func<IServiceProvider, TService> implementationFactory)
206
        where TService : class, IQueryGenerator
207
    {
208
        _queryGeneratorType = typeof(TService);
×
209
        _services.TryAddSingleton(implementationFactory);
×
210
        return this;
×
211
    }
212

213
    /// <summary>
214
    /// Adds the SQL server generator to use with this configuration.
215
    /// </summary>
216
    /// <returns>
217
    /// The same configuration builder so that multiple calls can be chained.
218
    /// </returns>
219
    public DataConfigurationBuilder AddSqlServerGenerator()
220
    {
221
        AddQueryGenerator<SqlServerGenerator>();
2✔
222
        return this;
2✔
223
    }
224

225
    /// <summary>
226
    /// Adds the sqlite generator to use with this configuration.
227
    /// </summary>
228
    /// <returns>
229
    /// The same configuration builder so that multiple calls can be chained.
230
    /// </returns>
231
    public DataConfigurationBuilder AddSqliteGenerator()
232
    {
233
        AddQueryGenerator<SqliteGenerator>();
1✔
234
        return this;
1✔
235
    }
236

237
    /// <summary>
238
    /// Adds the PostgreSQL generator to use with this configuration.
239
    /// </summary>
240
    /// <returns>
241
    /// The same configuration builder so that multiple calls can be chained.
242
    /// </returns>
243
    public DataConfigurationBuilder AddPostgreSqlGenerator()
244
    {
245
        AddQueryGenerator<PostgreSqlGenerator>();
1✔
246
        return this;
1✔
247
    }
248

249

250
    /// <summary>
251
    /// Adds the query logger service to use with this configuration.
252
    /// </summary>
253
    /// <typeparam name="TService">The type of the service.</typeparam>
254
    /// <param name="queryLogger">The query logger.</param>
255
    /// <returns>
256
    /// The same configuration builder so that multiple calls can be chained.
257
    /// </returns>
258
    /// <seealso cref="IDataQueryLogger"/>
259
    public DataConfigurationBuilder AddQueryLogger<TService>(TService queryLogger)
260
        where TService : class, IDataQueryLogger
261
    {
262
        _queryLoggerType = typeof(TService);
×
263
        _services.TryAddSingleton(queryLogger);
×
264
        return this;
×
265
    }
266

267
    /// <summary>
268
    /// Adds the query logger service to use with this configuration.
269
    /// </summary>
270
    /// <typeparam name="TService">The type of the service.</typeparam>
271
    /// <returns>
272
    /// The same configuration builder so that multiple calls can be chained.
273
    /// </returns>
274
    /// <seealso cref="IDataQueryLogger"/>
275
    public DataConfigurationBuilder AddQueryLogger<TService>()
276
        where TService : class, IDataQueryLogger
277
    {
278
        _queryLoggerType = typeof(TService);
×
279
        _services.TryAddSingleton<TService>();
×
280
        return this;
×
281
    }
282

283
    /// <summary>
284
    /// Adds the query logger service to use with this configuration.
285
    /// </summary>
286
    /// <typeparam name="TService">The type of the service.</typeparam>
287
    /// <param name="implementationFactory">The implementation factory.</param>
288
    /// <returns>
289
    /// The same configuration builder so that multiple calls can be chained.
290
    /// </returns>
291
    /// <seealso cref="IDataQueryLogger"/>
292
    public DataConfigurationBuilder AddQueryLogger<TService>(Func<IServiceProvider, TService> implementationFactory)
293
        where TService : class, IDataQueryLogger
294
    {
295
        _queryLoggerType = typeof(TService);
×
296
        _services.TryAddSingleton(implementationFactory);
×
297
        return this;
×
298
    }
299

300

301
    /// <summary>
302
    /// Adds services via the configuration setup action.
303
    /// </summary>
304
    /// <param name="setupAction">The configuration setup action.</param>
305
    /// <returns>
306
    /// The same configuration builder so that multiple calls can be chained.
307
    /// </returns>
308
    public DataConfigurationBuilder AddService(Action<IServiceCollection> setupAction)
309
    {
310
        setupAction(_services);
2✔
311
        return this;
2✔
312
    }
313

314
    /// <summary>
315
    /// Adds an interceptor instance to the configuration.
316
    /// </summary>
317
    /// <typeparam name="TService">The type of the interceptor.</typeparam>
318
    /// <param name="interceptor">The interceptor instance.</param>
319
    /// <returns>
320
    /// The same configuration builder so that multiple calls can be chained.
321
    /// </returns>
322
    /// <seealso cref="IDataInterceptor"/>
323
    public DataConfigurationBuilder AddInterceptor<TService>(TService interceptor)
324
        where TService : class, IDataInterceptor
325
    {
UNCOV
326
        _services.AddSingleton<IDataInterceptor>(interceptor);
×
UNCOV
327
        return this;
×
328
    }
329

330
    /// <summary>
331
    /// Adds an interceptor using a factory to the configuration.
332
    /// </summary>
333
    /// <typeparam name="TService">The type of the interceptor.</typeparam>
334
    /// <param name="implementationFactory">The factory that creates the interceptor.</param>
335
    /// <returns>
336
    /// The same configuration builder so that multiple calls can be chained.
337
    /// </returns>
338
    /// <seealso cref="IDataInterceptor"/>
339
    public DataConfigurationBuilder AddInterceptor<TService>(Func<IServiceProvider, TService> implementationFactory)
340
        where TService : class, IDataInterceptor
341
    {
UNCOV
342
        _services.AddSingleton<IDataInterceptor>(implementationFactory);
×
UNCOV
343
        return this;
×
344
    }
345

346
    /// <summary>
347
    /// Adds an interceptor by type to the configuration.
348
    /// </summary>
349
    /// <typeparam name="TService">The type of the interceptor.</typeparam>
350
    /// <returns>
351
    /// The same configuration builder so that multiple calls can be chained.
352
    /// </returns>
353
    /// <seealso cref="IDataInterceptor"/>
354
    public DataConfigurationBuilder AddInterceptor<TService>()
355
        where TService : class, IDataInterceptor
356
    {
UNCOV
357
        _services.AddSingleton<IDataInterceptor, TService>();
×
UNCOV
358
        return this;
×
359
    }
360

361

362
    internal void AddConfiguration()
363
    {
364
        RegisterDefaults();
3✔
365

366
        // resolve using specific types to support multiple configurations
367
        var providerFactory = _providerFactoryType ?? typeof(DbProviderFactory);
3!
368
        var dataCache = _dataCacheType ?? typeof(IDataCache);
3✔
369
        var queryGenerator = _queryGeneratorType ?? typeof(IQueryGenerator);
3!
370
        var queryLogger = _queryLoggerType ?? typeof(IDataQueryLogger);
3✔
371

372
        _services.TryAddSingleton<IDataConfiguration>(sp =>
3✔
373
        {
3✔
374
            var connectionString = ResolveConnectionString(sp, _nameOrConnectionString);
3✔
375

3✔
376
            return new DataConfiguration(
3✔
377
                sp.GetRequiredService(providerFactory) as DbProviderFactory,
3✔
378
                connectionString,
3✔
379
                sp.GetService(dataCache) as IDataCache,
3✔
380
                sp.GetService(queryGenerator) as IQueryGenerator,
3✔
381
                sp.GetService(queryLogger) as IDataQueryLogger,
3✔
382
                sp.GetServices<IDataInterceptor>()
3✔
383
            );
3✔
384
        });
3✔
385

386
        _services.TryAddTransient<IDataSessionFactory>(sp => sp.GetService<IDataConfiguration>());
4✔
387
        _services.TryAddTransient<IDataSession, DataSession>();
3✔
388
    }
3✔
389

390
    internal void AddConfiguration<TDiscriminator>()
391
    {
392
        RegisterDefaults();
1✔
393

394
        // resolve using specific types to support multiple configurations
395
        var providerFactory = _providerFactoryType ?? typeof(DbProviderFactory);
1!
396
        var dataCache = _dataCacheType ?? typeof(IDataCache);
1!
397
        var queryGenerator = _queryGeneratorType ?? typeof(IQueryGenerator);
1!
398
        var queryLogger = _queryLoggerType ?? typeof(IDataQueryLogger);
1✔
399

400
        _services.TryAddSingleton<IDataConfiguration<TDiscriminator>>(sp =>
1✔
401
        {
1✔
402
            var connectionString = ResolveConnectionString(sp, _nameOrConnectionString);
1✔
403

1✔
404
            return new DataConfiguration<TDiscriminator>(
1✔
405
                sp.GetRequiredService(providerFactory) as DbProviderFactory,
1✔
406
                connectionString,
1✔
407
                sp.GetService(dataCache) as IDataCache,
1✔
408
                sp.GetService(queryGenerator) as IQueryGenerator,
1✔
409
                sp.GetService(queryLogger) as IDataQueryLogger,
1✔
410
                sp.GetServices<IDataInterceptor>()
1✔
411
            );
1✔
412
        });
1✔
413

414
        _services.TryAddTransient<IDataSessionFactory<TDiscriminator>>(sp => sp.GetService<IDataConfiguration<TDiscriminator>>());
2✔
415
        _services.TryAddTransient<IDataSession<TDiscriminator>, DataSession<TDiscriminator>>();
1✔
416
    }
1✔
417

418
    private void RegisterDefaults()
419
    {
420
        // add defaults if not already added
421
        _services.TryAddSingleton<IDataQueryFormatter, DataQueryFormatter>();
4✔
422

423
        // convert specific types to interfaces
424
        if (_providerFactoryType != null)
4✔
425
            _services.TryAddSingleton(sp => sp.GetService(_providerFactoryType) as DbProviderFactory);
5✔
426

427
        if (_dataCacheType != null)
4✔
428
            _services.TryAddSingleton(sp => sp.GetService(_dataCacheType) as IDataCache);
3✔
429

430
        if (_queryGeneratorType != null)
4!
431
            _services.TryAddSingleton(sp => sp.GetService(_queryGeneratorType) as IQueryGenerator);
5✔
432
        else
UNCOV
433
            _services.TryAddSingleton<IQueryGenerator, SqlServerGenerator>();
×
434

435
        if (_queryLoggerType != null)
4!
UNCOV
436
            _services.TryAddSingleton(sp => sp.GetService(_queryLoggerType) as IDataQueryLogger);
×
437
        else
438
            _services.TryAddSingleton<IDataQueryLogger, DataQueryLogger>();
4✔
439

440
    }
4✔
441

442
    private static string ResolveConnectionString(IServiceProvider serviceProvider, string nameOrConnectionString)
443
    {
444
        var isConnectionString = nameOrConnectionString.IndexOfAny([';', '=']) > 0;
4✔
445
        if (isConnectionString)
4✔
446
            return nameOrConnectionString;
3✔
447

448
        var configuration = serviceProvider.GetRequiredService<IConfiguration>();
1✔
449

450
        // first try connection strings section
451
        var connectionString = configuration.GetConnectionString(nameOrConnectionString);
1✔
452
        if (connectionString.HasValue())
1!
453
            return connectionString;
1✔
454

455
        // next try root collection
UNCOV
456
        connectionString = configuration[nameOrConnectionString];
×
UNCOV
457
        if (connectionString.HasValue())
×
UNCOV
458
            return connectionString;
×
459

UNCOV
460
        return null;
×
461
    }
462
}
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