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

loresoft / FluentCommand / 26923300515

04 Jun 2026 01:03AM UTC coverage: 65.014% (+9.9%) from 55.157%
26923300515

push

github

pwelter34
Merge branch 'master' of https://github.com/loresoft/FluentCommand

1728 of 3450 branches covered (50.09%)

Branch coverage included in aggregate %.

5510 of 7683 relevant lines covered (71.72%)

297.61 hits per line

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

84.06
/src/FluentCommand/Query/QueryBuilder.cs
1
using System.Text;
2
using System.Text.Json;
3

4
using FluentCommand.Query.Generators;
5

6
namespace FluentCommand.Query;
7

8
/// <summary>
9
/// Provides a high-level builder for constructing and composing multiple SQL query statements.
10
/// </summary>
11
/// <seealso cref="FluentCommand.Query.IStatementBuilder" />
12
public class QueryBuilder : IStatementBuilder
13
{
14
    private readonly Queue<IStatementBuilder> _builderQueue = new();
90✔
15

16
    /// <summary>
17
    /// Initializes a new instance of the <see cref="QueryBuilder"/> class.
18
    /// </summary>
19
    /// <param name="queryGenerator">The <see cref="IQueryGenerator"/> used to generate SQL expressions and statements.</param>
20
    /// <param name="parameters">The initial list of <see cref="QueryParameter"/> objects for the query.</param>
21
    /// <exception cref="System.ArgumentNullException">
22
    /// Thrown if <paramref name="queryGenerator"/> or <paramref name="parameters"/> is <c>null</c>.
23
    /// </exception>
24
    public QueryBuilder(IQueryGenerator queryGenerator, List<QueryParameter> parameters)
90✔
25
    {
26
        QueryGenerator = queryGenerator ?? throw new ArgumentNullException(nameof(queryGenerator));
90!
27
        Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters));
90!
28
    }
90✔
29

30
    /// <summary>
31
    /// Gets the <see cref="IQueryGenerator"/> used to generate SQL expressions and statements.
32
    /// </summary>
33
    /// <value>
34
    /// The <see cref="IQueryGenerator"/> instance.
35
    /// </value>
36
    protected IQueryGenerator QueryGenerator { get; }
37

38
    /// <summary>
39
    /// Gets the list of <see cref="QueryParameter"/> objects used in the query.
40
    /// </summary>
41
    /// <value>
42
    /// The list of query parameters.
43
    /// </value>
44
    protected List<QueryParameter> Parameters { get; }
45

46
    /// <summary>
47
    /// Gets the JSON serializer options used by JSON value helpers.
48
    /// </summary>
49
    protected JsonSerializerOptions? JsonSerializerOptions { get; private set; }
50

51
    internal QueryBuilder UseJsonSerializerOptions(JsonSerializerOptions? options)
52
    {
53
        JsonSerializerOptions = options;
88✔
54
        return this;
88✔
55
    }
56

57

58
    /// <summary>
59
    /// Starts a new raw SQL statement builder and adds it to the query.
60
    /// </summary>
61
    /// <returns>
62
    /// A new <see cref="StatementBuilder"/> instance for building a raw SQL statement.
63
    /// </returns>
64
    public StatementBuilder Statement()
65
    {
66
        var builder = new StatementBuilder(QueryGenerator, Parameters)
3✔
67
            .UseJsonSerializerOptions(JsonSerializerOptions);
3✔
68

69
        _builderQueue.Enqueue(builder);
3✔
70

71
        return builder;
3✔
72
    }
73

74
    /// <summary>
75
    /// Starts a new SELECT statement builder for a specific entity type and adds it to the query.
76
    /// </summary>
77
    /// <typeparam name="TEntity">The type of the entity to select.</typeparam>
78
    /// <returns>
79
    /// A new <see cref="SelectEntityBuilder{TEntity}"/> instance for building a SELECT statement.
80
    /// </returns>
81
    public SelectEntityBuilder<TEntity> Select<TEntity>()
82
        where TEntity : class
83
    {
84
        var builder = new SelectEntityBuilder<TEntity>(QueryGenerator, Parameters);
41✔
85

86
        _builderQueue.Enqueue(builder);
41✔
87

88
        return builder;
41✔
89
    }
90

91
    /// <summary>
92
    /// Starts a new SELECT statement builder and adds it to the query.
93
    /// </summary>
94
    /// <returns>
95
    /// A new <see cref="SelectBuilder"/> instance for building a SELECT statement.
96
    /// </returns>
97
    public SelectBuilder Select()
98
    {
99
        var builder = new SelectBuilder(QueryGenerator, Parameters);
×
100

101
        _builderQueue.Enqueue(builder);
×
102

103
        return builder;
×
104

105
    }
106

107
    /// <summary>
108
    /// Starts a new INSERT statement builder for a specific entity type and adds it to the query.
109
    /// </summary>
110
    /// <typeparam name="TEntity">The type of the entity to insert.</typeparam>
111
    /// <returns>
112
    /// A new <see cref="InsertEntityBuilder{TEntity}"/> instance for building an INSERT statement.
113
    /// </returns>
114
    public InsertEntityBuilder<TEntity> Insert<TEntity>()
115
        where TEntity : class
116
    {
117
        var builder = new InsertEntityBuilder<TEntity>(QueryGenerator, Parameters)
11✔
118
            .UseJsonSerializerOptions(JsonSerializerOptions);
11✔
119

120
        _builderQueue.Enqueue(builder);
11✔
121

122
        return builder;
11✔
123
    }
124

125
    /// <summary>
126
    /// Starts a new INSERT statement builder and adds it to the query.
127
    /// </summary>
128
    /// <returns>
129
    /// A new <see cref="InsertBuilder"/> instance for building an INSERT statement.
130
    /// </returns>
131
    public InsertBuilder Insert()
132
    {
133
        var builder = new InsertBuilder(QueryGenerator, Parameters)
5✔
134
            .UseJsonSerializerOptions(JsonSerializerOptions);
5✔
135

136
        _builderQueue.Enqueue(builder);
5✔
137

138
        return builder;
5✔
139

140
    }
141

142
    /// <summary>
143
    /// Starts a new UPSERT statement builder for a specific entity type and adds it to the query.
144
    /// </summary>
145
    /// <typeparam name="TEntity">The type of the entity to insert or update.</typeparam>
146
    /// <returns>
147
    /// A new <see cref="UpsertEntityBuilder{TEntity}"/> instance for building an UPSERT statement.
148
    /// </returns>
149
    public UpsertEntityBuilder<TEntity> Upsert<TEntity>()
150
        where TEntity : class
151
    {
152
        var builder = new UpsertEntityBuilder<TEntity>(QueryGenerator, Parameters)
12✔
153
            .UseJsonSerializerOptions(JsonSerializerOptions);
12✔
154

155
        _builderQueue.Enqueue(builder);
12✔
156

157
        return builder;
12✔
158
    }
159

160
    /// <summary>
161
    /// Starts a new UPSERT statement builder and adds it to the query.
162
    /// </summary>
163
    /// <returns>
164
    /// A new <see cref="UpsertBuilder"/> instance for building an UPSERT statement.
165
    /// </returns>
166
    public UpsertBuilder Upsert()
167
    {
168
        var builder = new UpsertBuilder(QueryGenerator, Parameters)
11✔
169
            .UseJsonSerializerOptions(JsonSerializerOptions);
11✔
170

171
        _builderQueue.Enqueue(builder);
11✔
172

173
        return builder;
11✔
174

175
    }
176

177
    /// <summary>
178
    /// Starts a new UPDATE statement builder for a specific entity type and adds it to the query.
179
    /// </summary>
180
    /// <typeparam name="TEntity">The type of the entity to update.</typeparam>
181
    /// <returns>
182
    /// A new <see cref="UpdateEntityBuilder{TEntity}"/> instance for building an UPDATE statement.
183
    /// </returns>
184
    public UpdateEntityBuilder<TEntity> Update<TEntity>()
185
        where TEntity : class
186
    {
187
        var builder = new UpdateEntityBuilder<TEntity>(QueryGenerator, Parameters);
4✔
188

189
        _builderQueue.Enqueue(builder);
4✔
190

191
        return builder;
4✔
192

193
    }
194

195
    /// <summary>
196
    /// Starts a new UPDATE statement builder and adds it to the query.
197
    /// </summary>
198
    /// <returns>
199
    /// A new <see cref="UpdateBuilder"/> instance for building an UPDATE statement.
200
    /// </returns>
201
    public UpdateBuilder Update()
202
    {
203
        var builder = new UpdateBuilder(QueryGenerator, Parameters);
3✔
204

205
        _builderQueue.Enqueue(builder);
3✔
206

207
        return builder;
3✔
208
    }
209

210
    /// <summary>
211
    /// Starts a new DELETE statement builder for a specific entity type and adds it to the query.
212
    /// </summary>
213
    /// <typeparam name="TEntity">The type of the entity to delete.</typeparam>
214
    /// <returns>
215
    /// A new <see cref="DeleteEntityBuilder{TEntity}"/> instance for building a DELETE statement.
216
    /// </returns>
217
    public DeleteEntityBuilder<TEntity> Delete<TEntity>()
218
        where TEntity : class
219
    {
220
        var builder = new DeleteEntityBuilder<TEntity>(QueryGenerator, Parameters);
3✔
221

222
        _builderQueue.Enqueue(builder);
3✔
223

224
        return builder;
3✔
225

226
    }
227

228
    /// <summary>
229
    /// Starts a new DELETE statement builder and adds it to the query.
230
    /// </summary>
231
    /// <returns>
232
    /// A new <see cref="DeleteBuilder"/> instance for building a DELETE statement.
233
    /// </returns>
234
    public DeleteBuilder Delete()
235
    {
236
        var builder = new DeleteBuilder(QueryGenerator, Parameters);
×
237

238
        _builderQueue.Enqueue(builder);
×
239

240
        return builder;
×
241
    }
242

243
    /// <summary>
244
    /// Builds and returns a <see cref="QueryStatement"/> representing the composed SQL query and its parameters.
245
    /// </summary>
246
    /// <returns>
247
    /// A <see cref="QueryStatement"/> containing the SQL statement and associated <see cref="QueryParameter"/> values,
248
    /// or <c>null</c> if no statement can be built from the current configuration.
249
    /// </returns>
250
    public QueryStatement? BuildStatement()
251
    {
252
        // optimize for when only 1 builder
253
        if (_builderQueue.Count == 1)
90✔
254
        {
255
            var builder = _builderQueue.Dequeue();
88✔
256
            return builder.BuildStatement();
88✔
257
        }
258

259
        // merge all queued builders together
260
        var query = new StringBuilder();
2✔
261

262
        while (_builderQueue.Count > 0)
7✔
263
        {
264
            var builder = _builderQueue.Dequeue();
5✔
265
            var statement = builder.BuildStatement();
5✔
266

267
            if (statement != null)
5!
268
                query.AppendLine(statement.Statement);
5✔
269
        }
270

271
        if (query.Length == 0)
2!
272
            return null;
×
273

274
        return new QueryStatement(query.ToString(), Parameters);
2✔
275
    }
276
}
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