• 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

72.73
/src/FluentCommand/Query/StatementBuilder.cs
1
using System.Runtime.CompilerServices;
2
using System.Text.Json;
3

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

7
namespace FluentCommand.Query;
8

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

24
    /// <summary>
25
    /// Gets or sets the SQL query statement to be executed.
26
    /// </summary>
27
    /// <value>
28
    /// The SQL query statement as a <see cref="string"/>.
29
    /// </value>
30
    protected string Statement { get; set; } = string.Empty;
31

32
    /// <summary>
33
    /// Sets the SQL query statement for this builder.
34
    /// </summary>
35
    /// <param name="queryStatement">The SQL query statement as a <see cref="string"/>.</param>
36
    /// <returns>
37
    /// The current <see cref="StatementBuilder"/> instance for method chaining.
38
    /// </returns>
39
    public StatementBuilder Query(string queryStatement)
40
    {
41
        Statement = queryStatement;
3✔
42
        return this;
3✔
43
    }
44

45
    /// <summary>
46
    /// Adds a query parameter with the specified name and value to the builder.
47
    /// </summary>
48
    /// <typeparam name="TValue">The type of the parameter value.</typeparam>
49
    /// <param name="name">The name of the parameter.</param>
50
    /// <param name="value">The value of the parameter.</param>
51
    /// <returns>
52
    /// The current <see cref="StatementBuilder"/> instance for method chaining.
53
    /// </returns>
54
    public StatementBuilder Parameter<TValue>(string name, TValue? value)
55
    {
56
        var queryParam = new QueryParameter(name, value, typeof(TValue));
2✔
57
        Parameters.Add(queryParam);
2✔
58

59
        return this;
2✔
60
    }
61

62
    /// <inheritdoc />
63
    public override QueryStatement? BuildStatement()
64
    {
65
        return new QueryStatement(Statement, Parameters);
3✔
66
    }
67
}
68

69
/// <summary>
70
/// Provides a base class for building SQL query statements, supporting tagging, comments, and parameter management.
71
/// </summary>
72
/// <typeparam name="TBuilder">The type of the builder for fluent chaining.</typeparam>
73
public abstract class StatementBuilder<TBuilder> : IStatementBuilder, IQueryBuilder
74
    where TBuilder : StatementBuilder<TBuilder>
75
{
76
    /// <summary>
77
    /// Initializes a new instance of the <see cref="StatementBuilder{TBuilder}"/> class.
78
    /// </summary>
79
    /// <param name="queryGenerator">The <see cref="IQueryGenerator"/> used to generate SQL expressions and comments.</param>
80
    /// <param name="parameters">The initial list of <see cref="QueryParameter"/> objects for the query.</param>
81
    /// <exception cref="System.ArgumentNullException">
82
    /// Thrown if <paramref name="queryGenerator"/> or <paramref name="parameters"/> is <c>null</c>.
83
    /// </exception>
84
    protected StatementBuilder(IQueryGenerator queryGenerator, List<QueryParameter> parameters)
152✔
85
    {
86
        QueryGenerator = queryGenerator ?? throw new ArgumentNullException(nameof(queryGenerator));
152!
87
        Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters));
152!
88
    }
152✔
89

90
    /// <summary>
91
    /// Gets the <see cref="IQueryGenerator"/> used to generate SQL expressions and comments.
92
    /// </summary>
93
    /// <value>
94
    /// The <see cref="IQueryGenerator"/> instance.
95
    /// </value>
96
    protected IQueryGenerator QueryGenerator { get; }
97

98
    /// <summary>
99
    /// Gets the list of <see cref="QueryParameter"/> objects used in the query.
100
    /// </summary>
101
    /// <value>
102
    /// The list of query parameters.
103
    /// </value>
104
    protected List<QueryParameter> Parameters { get; }
105

106
    /// <summary>
107
    /// Gets the JSON serializer options used by JSON value helpers.
108
    /// </summary>
109
    protected JsonSerializerOptions? JsonSerializerOptions { get; private set; }
110

111
    internal TBuilder UseJsonSerializerOptions(JsonSerializerOptions? options)
112
    {
113
        JsonSerializerOptions = options;
42✔
114
        return (TBuilder)this;
42✔
115
    }
116

117
    /// <summary>
118
    /// Gets or sets the list of comment expressions to be included in the query.
119
    /// </summary>
120
    /// <value>
121
    /// The list of comment expressions.
122
    /// </value>
123
    protected List<string> CommentExpressions { get; set; } = new();
124

125
    /// <summary>
126
    /// Tags the query with a comment that includes the specified text, caller member name, source file, and line number.
127
    /// </summary>
128
    /// <param name="comment">The comment text to include in the tag. Defaults to "Caller".</param>
129
    /// <param name="memberName">The name of the calling member. Automatically provided by the compiler.</param>
130
    /// <param name="sourceFilePath">The source file path of the caller. Automatically provided by the compiler.</param>
131
    /// <param name="sourceLineNumber">The line number in the source file. Automatically provided by the compiler.</param>
132
    /// <returns>
133
    /// The current builder instance for method chaining.
134
    /// </returns>
135
    public TBuilder Tag(
136
        string comment = "Caller",
137
        [CallerMemberName] string memberName = "",
138
        [CallerFilePath] string sourceFilePath = "",
139
        [CallerLineNumber] int sourceLineNumber = 0)
140
    {
141
        // augment comment with source file and line number
142
        var fileName = Path.GetFileName(sourceFilePath);
36✔
143

144
        var commentMember = $"{comment}; {memberName}() in {fileName}:line {sourceLineNumber}";
36✔
145
        var commentExpression = QueryGenerator.CommentExpression(commentMember);
36✔
146

147
        CommentExpressions.Add(commentExpression);
36✔
148

149
        return (TBuilder)this;
36✔
150
    }
151

152
    /// <summary>
153
    /// Adds a custom comment to the query.
154
    /// </summary>
155
    /// <param name="comment">The comment text to add.</param>
156
    /// <returns>
157
    /// The current builder instance for method chaining.
158
    /// </returns>
159
    public TBuilder Comment(string? comment)
160
    {
161
        if (comment.IsNullOrWhiteSpace())
×
162
            return (TBuilder)this;
×
163

164
        var commentExpression = QueryGenerator.CommentExpression(comment);
×
165

166
        CommentExpressions.Add(commentExpression);
×
167

168
        return (TBuilder)this;
×
169
    }
170

171
    /// <inheritdoc />
172
    public abstract QueryStatement? BuildStatement();
173

174
    /// <summary>
175
    /// Generates the next unique parameter name for use in the query.
176
    /// </summary>
177
    /// <returns>
178
    /// A unique parameter name as a <see cref="string"/> (e.g., "@p0001").
179
    /// </returns>
180
    protected string NextParameter() => $"@p{Parameters.Count:0000}";
456✔
181

182
    /// <inheritdoc />
183
    IQueryGenerator IQueryBuilder.QueryGenerator => QueryGenerator;
3✔
184

185
    /// <inheritdoc />
186
    List<QueryParameter> IQueryBuilder.Parameters => Parameters;
3✔
187
}
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