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

loresoft / FluentCommand / 6648415992

26 Oct 2023 01:49AM UTC coverage: 51.645% (+0.1%) from 51.515%
6648415992

push

github

pwelter34
Update InsertBuilder.cs

981 of 2442 branches covered (0.0%)

Branch coverage included in aggregate %.

2896 of 5065 relevant lines covered (57.18%)

156.37 hits per line

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

45.22
/src/FluentCommand/Query/SelectBuilder.cs
1
using FluentCommand.Extensions;
2
using FluentCommand.Query.Generators;
3
using FluentCommand.Reflection;
4

5
namespace FluentCommand.Query;
6

7
/// <summary>
8
/// Select query builder
9
/// </summary>
10
public class SelectBuilder : SelectBuilder<SelectBuilder>
11
{
12
    /// <summary>
13
    /// Initializes a new instance of the <see cref="SelectBuilder"/> class.
14
    /// </summary>
15
    /// <param name="queryGenerator">The query generator.</param>
16
    /// <param name="parameters">The query parameters.</param>
17
    /// <param name="logicalOperator">The logical operator.</param>
18
    public SelectBuilder(
19
        IQueryGenerator queryGenerator,
20
        List<QueryParameter> parameters,
21
        LogicalOperators logicalOperator = LogicalOperators.And)
22
        : base(queryGenerator, parameters, logicalOperator)
×
23
    {
24
    }
×
25
}
26

27
/// <summary>
28
/// Select query builder
29
/// </summary>
30
public abstract class SelectBuilder<TBuilder> : WhereBuilder<TBuilder>
31
    where TBuilder : SelectBuilder<TBuilder>
32
{
33
    /// <summary>
34
    /// Initializes a new instance of the <see cref="SelectBuilder{TBuilder}"/> class.
35
    /// </summary>
36
    /// <param name="queryGenerator">The query generator.</param>
37
    /// <param name="parameters">The query parameters.</param>
38
    /// <param name="logicalOperator">The logical operator.</param>
39
    protected SelectBuilder(
40
        IQueryGenerator queryGenerator,
41
        List<QueryParameter> parameters,
42
        LogicalOperators logicalOperator = LogicalOperators.And)
43
        : base(queryGenerator, parameters, logicalOperator)
47✔
44
    {
45
    }
47✔
46

47
    /// <summary>
48
    /// Gets the select expressions.
49
    /// </summary>
50
    /// <value>
51
    /// The select expressions.
52
    /// </value>
53
    protected HashSet<ColumnExpression> SelectExpressions { get; } = new();
47✔
54

55
    /// <summary>
56
    /// Gets from expressions.
57
    /// </summary>
58
    /// <value>
59
    /// From expressions.
60
    /// </value>
61
    protected HashSet<TableExpression> FromExpressions { get; } = new();
47✔
62

63
    /// <summary>
64
    /// Gets the sort expressions.
65
    /// </summary>
66
    /// <value>
67
    /// The sort expressions.
68
    /// </value>
69
    protected HashSet<SortExpression> SortExpressions { get; } = new();
47✔
70

71
    /// <summary>
72
    /// Gets the group expressions.
73
    /// </summary>
74
    /// <value>
75
    /// The group expressions.
76
    /// </value>
77
    protected HashSet<GroupExpression> GroupExpressions { get; } = new();
47✔
78

79
    /// <summary>
80
    /// Gets the join expressions.
81
    /// </summary>
82
    /// <value>
83
    /// The join expressions.
84
    /// </value>
85
    protected HashSet<JoinExpression> JoinExpressions { get; } = new();
47✔
86

87
    /// <summary>
88
    /// Gets the limit expressions.
89
    /// </summary>
90
    /// <value>
91
    /// The limit expressions.
92
    /// </value>
93
    protected HashSet<LimitExpression> LimitExpressions { get; } = new();
47✔
94

95

96
    /// <summary>
97
    /// Adds a column expression with the specified name.
98
    /// </summary>
99
    /// <param name="columnName">Name of the column.</param>
100
    /// <param name="tableAlias">The table alias.</param>
101
    /// <param name="columnAlias">The column alias.</param>
102
    /// <returns>
103
    /// The same builder so that multiple calls can be chained.
104
    /// </returns>
105
    public TBuilder Column(
106
        string columnName,
107
        string tableAlias = null,
108
        string columnAlias = null)
109
    {
110
        var selectClause = new ColumnExpression(columnName, tableAlias, columnAlias);
98✔
111

112
        SelectExpressions.Add(selectClause);
98✔
113

114
        return (TBuilder)this;
98✔
115
    }
116

117
    /// <summary>
118
    /// Conditionally adds a column expression with the specified name.
119
    /// </summary>
120
    /// <param name="columnName">Name of the column.</param>
121
    /// <param name="tableAlias">The table alias.</param>
122
    /// <param name="columnAlias">The column alias.</param>
123
    /// <param name="condition">The condition.</param>
124
    /// <returns>
125
    /// The same builder so that multiple calls can be chained.
126
    /// </returns>
127
    public TBuilder ColumnIf(
128
        string columnName,
129
        string tableAlias = null,
130
        string columnAlias = null,
131
        Func<string, bool> condition = null)
132
    {
133
        if (condition != null && !condition(columnName))
×
134
            return (TBuilder)this;
×
135

136
        return Column(columnName, tableAlias, columnAlias);
×
137
    }
138

139
    /// <summary>
140
    /// Adds a column expression for each of specified names.
141
    /// </summary>
142
    /// <param name="columnNames">The column names.</param>
143
    /// <param name="tableAlias">The table alias.</param>
144
    /// <returns>
145
    /// The same builder so that multiple calls can be chained.
146
    /// </returns>
147
    /// <exception cref="System.ArgumentNullException">columnNames</exception>
148
    public virtual TBuilder Columns(
149
        IEnumerable<string> columnNames,
150
        string tableAlias = null)
151
    {
152
        if (columnNames is null)
×
153
            throw new ArgumentNullException(nameof(columnNames));
×
154

155
        foreach (var column in columnNames)
×
156
            Column(column, tableAlias);
×
157

158
        return (TBuilder)this;
×
159
    }
160

161

162
    /// <summary>
163
    /// Adds a count expression using the specified column name.
164
    /// </summary>
165
    /// <param name="columnName">Name of the column.</param>
166
    /// <param name="tableAlias">The table alias.</param>
167
    /// <param name="columnAlias">The column alias.</param>
168
    /// <returns>
169
    /// The same builder so that multiple calls can be chained.
170
    /// </returns>
171
    public TBuilder Count(
172
        string columnName = "*",
173
        string tableAlias = null,
174
        string columnAlias = null)
175
    {
176
        var selectClause = new AggregateExpression(AggregateFunctions.Count, columnName, tableAlias, columnAlias);
3✔
177

178
        SelectExpressions.Add(selectClause);
3✔
179

180
        return (TBuilder)this;
3✔
181
    }
182

183
    /// <summary>
184
    /// Adds an aggregate expression using the specified function and column name.
185
    /// </summary>
186
    /// <param name="function">The aggregate function.</param>
187
    /// <param name="columnName">Name of the column.</param>
188
    /// <param name="tableAlias">The table alias.</param>
189
    /// <param name="columnAlias">The column alias.</param>
190
    /// <returns>
191
    /// The same builder so that multiple calls can be chained.
192
    /// </returns>
193
    public TBuilder Aggregate(
194
        AggregateFunctions function,
195
        string columnName,
196
        string tableAlias = null,
197
        string columnAlias = null)
198
    {
199
        var selectClause = new AggregateExpression(function, columnName, tableAlias, columnAlias);
3✔
200

201
        SelectExpressions.Add(selectClause);
3✔
202

203
        return (TBuilder)this;
3✔
204
    }
205

206

207
    /// <summary>
208
    /// Add a from clause to the query.
209
    /// </summary>
210
    /// <param name="tableName">Name of the table.</param>
211
    /// <param name="tableSchema">The table schema.</param>
212
    /// <param name="tableAlias">The table alias.</param>
213
    /// <returns>
214
    /// The same builder so that multiple calls can be chained.
215
    /// </returns>
216
    public virtual TBuilder From(
217
        string tableName,
218
        string tableSchema = null,
219
        string tableAlias = null)
220
    {
221
        var fromClause = new TableExpression(tableName, tableSchema, tableAlias);
44✔
222

223
        FromExpressions.Add(fromClause);
44✔
224

225
        return (TBuilder)this;
44✔
226
    }
227

228
    /// <summary>
229
    /// Add a from clause to the query.
230
    /// </summary>
231
    /// <typeparam name="TEntity">The type of the entity.</typeparam>
232
    /// <param name="tableAlias">The table alias.</param>
233
    /// <returns>
234
    /// The same builder so that multiple calls can be chained.
235
    /// </returns>
236
    public TBuilder From<TEntity>(
237
        string tableAlias = null)
238
    {
239
        var typeAccessor = TypeAccessor.GetAccessor<TEntity>();
×
240

241
        var fromClause = new TableExpression(typeAccessor.TableName, typeAccessor.TableSchema, tableAlias);
×
242

243
        FromExpressions.Add(fromClause);
×
244

245
        return (TBuilder)this;
×
246
    }
247

248

249
    /// <summary>
250
    /// Add a raw from clause to the query.
251
    /// </summary>
252
    /// <param name="fromClause">From clause.</param>
253
    /// <returns>
254
    /// The same builder so that multiple calls can be chained.
255
    /// </returns>
256
    public TBuilder FromRaw(string fromClause)
257
    {
258
        if (fromClause.HasValue())
3✔
259
            FromExpressions.Add(new TableExpression(fromClause, IsRaw: true));
3✔
260

261
        return (TBuilder)this;
3✔
262
    }
263

264

265
    /// <summary>
266
    /// Add a join clause using the specified builder action
267
    /// </summary>
268
    /// <param name="builder">The builder.</param>
269
    /// <returns>
270
    /// The same builder so that multiple calls can be chained.
271
    /// </returns>
272
    public TBuilder Join(Action<JoinBuilder> builder)
273
    {
274
        var innerBuilder = new JoinBuilder(QueryGenerator, Parameters);
1✔
275
        builder(innerBuilder);
1✔
276

277
        JoinExpressions.Add(innerBuilder.BuildExpression());
1✔
278

279
        return (TBuilder)this;
1✔
280
    }
281

282

283
    /// <summary>
284
    /// Add an order by clause with the specified column name and sort direction.
285
    /// </summary>
286
    /// <param name="columnName">Name of the column.</param>
287
    /// <param name="sortDirection">The sort direction.</param>
288
    /// <returns>
289
    /// The same builder so that multiple calls can be chained.
290
    /// </returns>
291
    public TBuilder OrderBy(
292
        string columnName,
293
        SortDirections sortDirection = SortDirections.Ascending)
294
    {
295
        return OrderBy(columnName, null, sortDirection);
4✔
296
    }
297

298
    /// <summary>
299
    /// Add an order by clause with the specified column name, sort direction and table alias.
300
    /// </summary>
301
    /// <param name="columnName">Name of the column.</param>
302
    /// <param name="tableAlias">The table alias.</param>
303
    /// <param name="sortDirection">The sort direction.</param>
304
    /// <returns>
305
    /// The same builder so that multiple calls can be chained.
306
    /// </returns>
307
    public TBuilder OrderBy(
308
        string columnName,
309
        string tableAlias,
310
        SortDirections sortDirection = SortDirections.Ascending)
311
    {
312
        var orderClause = new SortExpression(columnName, tableAlias, sortDirection);
29✔
313

314
        SortExpressions.Add(orderClause);
29✔
315

316
        return (TBuilder)this;
29✔
317
    }
318

319
    /// <summary>
320
    /// Conditionally add an order by clause with the specified column name and sort direction.
321
    /// </summary>
322
    /// <param name="columnName">Name of the column.</param>
323
    /// <param name="sortDirection">The sort direction.</param>
324
    /// <param name="condition">The condition.</param>
325
    /// <returns>
326
    /// The same builder so that multiple calls can be chained.
327
    /// </returns>
328
    public TBuilder OrderByIf(
329
        string columnName,
330
        SortDirections sortDirection = SortDirections.Ascending,
331
        Func<string, bool> condition = null)
332
    {
333
        return OrderByIf(columnName, null, sortDirection, condition);
×
334
    }
335

336
    /// <summary>
337
    /// Conditionally add an order by clause with the specified column name, sort direction and table alias.
338
    /// </summary>
339
    /// <param name="columnName">Name of the column.</param>
340
    /// <param name="tableAlias">The table alias.</param>
341
    /// <param name="sortDirection">The sort direction.</param>
342
    /// <param name="condition">The condition.</param>
343
    /// <returns>
344
    /// The same builder so that multiple calls can be chained.
345
    /// </returns>
346
    public TBuilder OrderByIf(
347
        string columnName,
348
        string tableAlias,
349
        SortDirections sortDirection = SortDirections.Ascending,
350
        Func<string, bool> condition = null)
351
    {
352
        if (condition != null && !condition(columnName))
×
353
            return (TBuilder)this;
×
354

355
        return OrderBy(columnName, tableAlias, sortDirection);
×
356
    }
357

358
    /// <summary>
359
    /// Add a raw order by clause to the query.
360
    /// </summary>
361
    /// <param name="sortExpression">The order by clause.</param>
362
    /// <returns>
363
    /// The same builder so that multiple calls can be chained.
364
    /// </returns>
365
    public TBuilder OrderByRaw(string sortExpression)
366
    {
367
        if (sortExpression.HasValue())
×
368
            SortExpressions.Add(new SortExpression(sortExpression, IsRaw: true));
×
369

370
        return (TBuilder)this;
×
371
    }
372

373
    /// <summary>
374
    /// Conditionally add a raw order by clause to the query.
375
    /// </summary>
376
    /// <param name="sortExpression">The order by clause.</param>
377
    /// <param name="condition">The condition.</param>
378
    /// <returns>
379
    /// The same builder so that multiple calls can be chained.
380
    /// </returns>
381
    public TBuilder OrderByRawIf(
382
        string sortExpression,
383
        Func<string, bool> condition = null)
384
    {
385
        if (condition != null && !condition(sortExpression))
×
386
            return (TBuilder)this;
×
387

388
        return OrderByRaw(sortExpression);
×
389
    }
390

391
    /// <summary>
392
    /// Add multiple raw order by clauses to the query.
393
    /// </summary>
394
    /// <param name="sortExpressions">The order by clauses.</param>
395
    /// <returns>
396
    /// The same builder so that multiple calls can be chained.
397
    /// </returns>
398
    public TBuilder OrderByRaw(IEnumerable<string> sortExpressions)
399
    {
400
        if (sortExpressions is null)
×
401
            throw new ArgumentNullException(nameof(sortExpressions));
×
402

403
        foreach (var sortExpression in sortExpressions)
×
404
            SortExpressions.Add(new SortExpression(sortExpression, IsRaw: true));
×
405

406
        return (TBuilder)this;
×
407
    }
408

409

410
    /// <summary>
411
    /// Adds a group by clause with the specified column name
412
    /// </summary>
413
    /// <param name="columnName">Name of the column.</param>
414
    /// <param name="tableAlias">The table alias.</param>
415
    /// <returns>
416
    /// The same builder so that multiple calls can be chained.
417
    /// </returns>
418
    public TBuilder GroupBy(
419
        string columnName,
420
        string tableAlias = null)
421
    {
422
        var orderClause = new GroupExpression(columnName, tableAlias);
3✔
423

424
        GroupExpressions.Add(orderClause);
3✔
425

426
        return (TBuilder)this;
3✔
427
    }
428

429

430
    /// <summary>
431
    /// Adds a limit expression with specified offset and size.
432
    /// </summary>
433
    /// <param name="offset">The offset.</param>
434
    /// <param name="size">The size.</param>
435
    /// <returns>
436
    /// The same builder so that multiple calls can be chained.
437
    /// </returns>
438
    public TBuilder Limit(int offset = 0, int size = 0)
439
    {
440
        // no paging
441
        if (size <= 0)
15!
442
            return (TBuilder)this;
×
443

444
        var limitClause = new LimitExpression(offset, size);
15✔
445
        LimitExpressions.Add(limitClause);
15✔
446

447
        return (TBuilder)this;
15✔
448
    }
449

450
    /// <summary>
451
    /// Adds a page limit expression with specified page and page size.
452
    /// </summary>
453
    /// <param name="page">The page number.</param>
454
    /// <param name="pageSize">Size of the page.</param>
455
    /// <returns>
456
    /// The same builder so that multiple calls can be chained.
457
    /// </returns>
458
    public TBuilder Page(int page = 0, int pageSize = 0)
459
    {
460
        // no paging
461
        if (pageSize <= 0 || page <= 0)
×
462
            return (TBuilder)this;
×
463

464
        int offset = Math.Max(pageSize * (page - 1), 0);
×
465
        var limitClause = new LimitExpression(offset, pageSize);
×
466

467
        LimitExpressions.Add(limitClause);
×
468

469
        return (TBuilder)this;
×
470
    }
471

472
    /// <inheritdoc />
473
    public override QueryStatement BuildStatement()
474
    {
475
        var selectStatement = new SelectStatement(
47✔
476
            SelectExpressions,
47✔
477
            FromExpressions,
47✔
478
            JoinExpressions,
47✔
479
            WhereExpressions,
47✔
480
            SortExpressions,
47✔
481
            GroupExpressions,
47✔
482
            LimitExpressions,
47✔
483
            CommentExpressions);
47✔
484

485
        var statement = QueryGenerator.BuildSelect(selectStatement);
47✔
486

487
        return new QueryStatement(statement, Parameters);
47✔
488
    }
489
}
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