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

loresoft / FluentCommand / 26594986582

28 May 2026 06:28PM UTC coverage: 55.553%. First build
26594986582

push

github

pwelter34
Move JSON support, add docs and examples

1358 of 3215 branches covered (42.24%)

Branch coverage included in aggregate %.

103 of 234 new or added lines in 9 files covered. (44.02%)

4389 of 7130 relevant lines covered (61.56%)

312.88 hits per line

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

53.13
/src/FluentCommand/Query/InsertBuilder.cs
1
using System.Text.Json;
2
using System.Text.Json.Serialization.Metadata;
3

4
using FluentCommand.Query.Generators;
5

6
namespace FluentCommand.Query;
7

8
/// <summary>
9
/// Provides a builder for constructing SQL INSERT statements with fluent, chainable methods.
10
/// </summary>
11
public class InsertBuilder : InsertBuilder<InsertBuilder>
12
{
13
    /// <summary>
14
    /// Initializes a new instance of the <see cref="InsertBuilder"/> class.
15
    /// </summary>
16
    /// <param name="queryGenerator">The <see cref="IQueryGenerator"/> used to generate SQL expressions.</param>
17
    /// <param name="parameters">The list of <see cref="QueryParameter"/> objects for the query.</param>
18
    public InsertBuilder(
19
        IQueryGenerator queryGenerator,
20
        List<QueryParameter> parameters)
21
        : base(queryGenerator, parameters)
4✔
22
    { }
4✔
23
}
24

25
/// <summary>
26
/// Provides a generic base class for building SQL INSERT statements with fluent, chainable methods.
27
/// </summary>
28
/// <typeparam name="TBuilder">The type of the builder for fluent chaining.</typeparam>
29
public abstract class InsertBuilder<TBuilder> : StatementBuilder<TBuilder>
30
    where TBuilder : InsertBuilder<TBuilder>
31
{
32
    /// <summary>
33
    /// Initializes a new instance of the <see cref="InsertBuilder{TBuilder}"/> class.
34
    /// </summary>
35
    /// <param name="queryGenerator">The <see cref="IQueryGenerator"/> used to generate SQL expressions.</param>
36
    /// <param name="parameters">The list of <see cref="QueryParameter"/> objects for the query.</param>
37
    protected InsertBuilder(
38
        IQueryGenerator queryGenerator,
39
        List<QueryParameter> parameters)
40
        : base(queryGenerator, parameters)
16✔
41
    {
42
    }
16✔
43

44
    /// <summary>
45
    /// Gets the collection of column expressions for the INSERT statement.
46
    /// </summary>
47
    /// <value>
48
    /// A <see cref="HashSet{ColumnExpression}"/> containing the column expressions.
49
    /// </value>
50
    protected HashSet<ColumnExpression> ColumnExpressions { get; } = new();
51

52
    /// <summary>
53
    /// Gets the collection of output column expressions for the INSERT statement.
54
    /// </summary>
55
    /// <value>
56
    /// A <see cref="HashSet{ColumnExpression}"/> containing the output column expressions.
57
    /// </value>
58
    protected HashSet<ColumnExpression> OutputExpressions { get; } = new();
59

60
    /// <summary>
61
    /// Gets the collection of value expressions for the INSERT statement.
62
    /// </summary>
63
    /// <value>
64
    /// A <see cref="HashSet{String}"/> containing the value expressions (parameter names).
65
    /// </value>
66
    protected HashSet<string> ValueExpressions { get; } = new();
67

68
    /// <summary>
69
    /// Gets the target table expression for the INSERT statement.
70
    /// </summary>
71
    /// <value>
72
    /// The <see cref="TableExpression"/> representing the target table.
73
    /// </value>
74
    protected TableExpression? TableExpression { get; private set; }
75

76
    /// <summary>
77
    /// Sets the target table to insert into.
78
    /// </summary>
79
    /// <param name="tableName">The name of the table.</param>
80
    /// <param name="tableSchema">The schema of the table (optional).</param>
81
    /// <param name="tableAlias">The alias for the table (optional).</param>
82
    /// <returns>
83
    /// The same builder instance for method chaining.
84
    /// </returns>
85
    public TBuilder Into(
86
        string tableName,
87
        string? tableSchema = null,
88
        string? tableAlias = null)
89
    {
90
        TableExpression = new TableExpression(tableName, tableSchema, tableAlias);
16✔
91

92
        return (TBuilder)this;
16✔
93
    }
94

95
    /// <summary>
96
    /// Adds a value for the specified column name and value.
97
    /// </summary>
98
    /// <typeparam name="TValue">The type of the value.</typeparam>
99
    /// <param name="columnName">The name of the column.</param>
100
    /// <param name="parameterValue">The value to insert for the column.</param>
101
    /// <returns>
102
    /// The same builder instance for method chaining.
103
    /// </returns>
104
    public TBuilder Value<TValue>(
105
        string columnName,
106
        TValue? parameterValue)
107
    {
108
        return Value(columnName, parameterValue, typeof(TValue));
25✔
109
    }
110

111
    /// <summary>
112
    /// Adds a value for the specified column name, value, and type.
113
    /// </summary>
114
    /// <param name="columnName">The name of the column.</param>
115
    /// <param name="parameterValue">The value to insert for the column.</param>
116
    /// <param name="parameterType">The type of the parameter value.</param>
117
    /// <returns>
118
    /// The same builder instance for method chaining.
119
    /// </returns>
120
    /// <exception cref="ArgumentException">Thrown if <paramref name="columnName"/> is null or empty.</exception>
121
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="parameterType"/> is <c>null</c>.</exception>
122
    public TBuilder Value(
123
        string columnName,
124
        object? parameterValue,
125
        Type parameterType)
126
    {
127
        ArgumentException.ThrowIfNullOrWhiteSpace(columnName);
177✔
128
        ArgumentNullException.ThrowIfNull(parameterType);
177✔
129

130
        var paramterName = NextParameter();
177✔
131

132
        var columnExpression = new ColumnExpression(columnName);
177✔
133

134
        ColumnExpressions.Add(columnExpression);
177✔
135
        ValueExpressions.Add(paramterName);
177✔
136

137
        QueryParameter parameter = new(paramterName, parameterValue, parameterType);
177✔
138
        Parameters.Add(parameter);
177✔
139

140
        return (TBuilder)this;
177✔
141
    }
142

143
    /// <summary>
144
    /// Conditionally adds a value for the specified column name and value if the condition is met.
145
    /// </summary>
146
    /// <typeparam name="TValue">The type of the value.</typeparam>
147
    /// <param name="columnName">The name of the column.</param>
148
    /// <param name="parameterValue">The value to insert for the column.</param>
149
    /// <param name="condition">A function that determines whether to add the value, based on the column name and value. If <c>null</c>, the value is always added.</param>
150
    /// <returns>
151
    /// The same builder instance for method chaining.
152
    /// </returns>
153
    public TBuilder ValueIf<TValue>(
154
        string columnName,
155
        TValue? parameterValue,
156
        Func<string, TValue?, bool> condition)
157
    {
158
        if (condition != null && !condition(columnName, parameterValue))
×
159
            return (TBuilder)this;
×
160

161
        return Value(columnName, parameterValue);
×
162
    }
163

164
    /// <summary>
165
    /// Adds a value for the specified column name with the value serialized as JSON using the specified <paramref name="options" />.
166
    /// </summary>
167
    /// <typeparam name="TValue">The type of the value.</typeparam>
168
    /// <param name="columnName">The name of the column.</param>
169
    /// <param name="parameterValue">The value to serialize as JSON and insert for the column.</param>
170
    /// <param name="options">The <see cref="JsonSerializerOptions"/> to use when serializing.</param>
171
    /// <returns>
172
    /// The same builder instance for method chaining.
173
    /// </returns>
174
    public TBuilder ValueJson<TValue>(
175
        string columnName,
176
        TValue? parameterValue,
177
        JsonSerializerOptions? options = null)
178
    {
179
        var json = parameterValue is not null
4!
180
            ? JsonSerializer.Serialize(parameterValue, options)
4✔
181
            : null;
4✔
182

183
        return Value(columnName, json);
4✔
184
    }
185

186
    /// <summary>
187
    /// Adds a value for the specified column name with the value serialized as JSON using the specified <paramref name="jsonTypeInfo" />.
188
    /// </summary>
189
    /// <typeparam name="TValue">The type of the value.</typeparam>
190
    /// <param name="columnName">The name of the column.</param>
191
    /// <param name="parameterValue">The value to serialize as JSON and insert for the column.</param>
192
    /// <param name="jsonTypeInfo">The <see cref="JsonTypeInfo{T}"/> to use when serializing.</param>
193
    /// <returns>
194
    /// The same builder instance for method chaining.
195
    /// </returns>
196
    public TBuilder ValueJson<TValue>(
197
        string columnName,
198
        TValue? parameterValue,
199
        JsonTypeInfo<TValue> jsonTypeInfo)
200
    {
NEW
201
        ArgumentNullException.ThrowIfNull(jsonTypeInfo);
×
202

NEW
203
        var json = parameterValue is not null
×
NEW
204
            ? JsonSerializer.Serialize(parameterValue, jsonTypeInfo)
×
NEW
205
            : null;
×
206

NEW
207
        return Value(columnName, json);
×
208
    }
209

210

211
    /// <summary>
212
    /// Adds an OUTPUT clause for the specified column names.
213
    /// </summary>
214
    /// <param name="columnNames">The collection of column names to include in the OUTPUT clause.</param>
215
    /// <param name="tableAlias">The alias for the table (optional).</param>
216
    /// <returns>
217
    /// The same builder instance for method chaining.
218
    /// </returns>
219
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="columnNames"/> is <c>null</c>.</exception>
220
    public TBuilder Output(
221
        IEnumerable<string> columnNames,
222
        string? tableAlias = null)
223
    {
NEW
224
        ArgumentNullException.ThrowIfNull(columnNames);
×
225

226
        foreach (var column in columnNames)
×
227
            Output(column, tableAlias);
×
228

229
        return (TBuilder)this;
×
230
    }
231

232
    /// <summary>
233
    /// Adds an OUTPUT clause for the specified column name.
234
    /// </summary>
235
    /// <param name="columnName">The name of the column to include in the OUTPUT clause.</param>
236
    /// <param name="tableAlias">The alias for the table (optional).</param>
237
    /// <param name="columnAlias">The alias for the output column (optional).</param>
238
    /// <returns>
239
    /// The same builder instance for method chaining.
240
    /// </returns>
241
    public TBuilder Output(
242
        string columnName,
243
        string? tableAlias = null,
244
        string? columnAlias = null)
245
    {
246
        var outputClause = new ColumnExpression(columnName, tableAlias, columnAlias);
11✔
247

248
        OutputExpressions.Add(outputClause);
11✔
249

250
        return (TBuilder)this;
11✔
251
    }
252

253
    /// <summary>
254
    /// Conditionally adds an OUTPUT clause for the specified column name if the condition is met.
255
    /// </summary>
256
    /// <param name="columnName">The name of the column to include in the OUTPUT clause.</param>
257
    /// <param name="tableAlias">The alias for the table (optional).</param>
258
    /// <param name="columnAlias">The alias for the output column (optional).</param>
259
    /// <param name="condition">A function that determines whether to add the OUTPUT clause. If <c>null</c>, the clause is always added.</param>
260
    /// <returns>
261
    /// The same builder instance for method chaining.
262
    /// </returns>
263
    public TBuilder OutputIf(
264
        string columnName,
265
        string? tableAlias = null,
266
        string? columnAlias = null,
267
        Func<string, bool>? condition = null)
268
    {
269
        if (condition != null && !condition(columnName))
×
270
            return (TBuilder)this;
×
271

272
        return Output(columnName, tableAlias, columnAlias);
×
273
    }
274

275
    /// <summary>
276
    /// Builds the SQL INSERT statement using the current configuration.
277
    /// </summary>
278
    /// <returns>
279
    /// A <see cref="QueryStatement"/> containing the SQL INSERT statement and its parameters.
280
    /// </returns>
281
    public override QueryStatement? BuildStatement()
282
    {
283
        if (TableExpression is null)
16!
284
            throw new InvalidOperationException("Table must be specified before building an insert statement.");
×
285

286
        var insertStatement = new InsertStatement(
16✔
287
            TableExpression,
16✔
288
            ColumnExpressions,
16✔
289
            OutputExpressions,
16✔
290
            ValueExpressions,
16✔
291
            CommentExpressions);
16✔
292

293
        var statement = QueryGenerator.BuildInsert(insertStatement);
16✔
294

295
        return new QueryStatement(statement, Parameters);
16✔
296
    }
297
}
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