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

loresoft / FluentCommand / 26594173245

28 May 2026 06:28PM UTC coverage: 55.553% (+0.7%) from 54.902%
26594173245

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%)

371 existing lines in 26 files now uncovered.

4389 of 7130 relevant lines covered (61.56%)

312.89 hits per line

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

69.71
/src/FluentCommand/Query/Generators/SqliteGenerator.cs
1
using FluentCommand.Extensions;
2
using FluentCommand.Internal;
3

4
namespace FluentCommand.Query.Generators;
5

6
/// <summary>
7
/// Provides a SQL generator for SQLite, implementing SQL statement and expression generation
8
/// with SQLite-specific syntax and conventions.
9
/// </summary>
10
public class SqliteGenerator : SqlServerGenerator
11
{
12
    /// <summary>
13
    /// Builds a SQL INSERT statement for SQLite, including support for RETURNING and comments.
14
    /// </summary>
15
    /// <param name="insertStatement">The <see cref="InsertStatement"/> containing the INSERT statement configuration.</param>
16
    /// <returns>A SQL INSERT statement string for SQLite.</returns>
17
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="insertStatement"/> is <c>null</c>.</exception>
18
    /// <exception cref="ArgumentException">Thrown if the table or values are not specified.</exception>
19
    public override string BuildInsert(InsertStatement insertStatement)
20
    {
21
        ArgumentNullException.ThrowIfNull(insertStatement);
4✔
22

23
        if (insertStatement.TableExpression == null)
4!
UNCOV
24
            throw new ArgumentException("No table specified to insert into", nameof(insertStatement));
×
25

26
        if (insertStatement.ValueExpressions == null || insertStatement.ValueExpressions.Count == 0)
4!
UNCOV
27
            throw new ArgumentException("No values specified for insert", nameof(insertStatement));
×
28

29
        var insertBuilder = StringBuilderCache.Acquire();
4✔
30

31
        if (insertStatement.CommentExpressions?.Count > 0)
4!
32
        {
33
            insertBuilder
3✔
34
                .AppendJoin(Environment.NewLine, insertStatement.CommentExpressions)
3✔
35
                .AppendLine();
3✔
36
        }
37

38
        var table = TableExpression(insertStatement.TableExpression);
4✔
39
        insertBuilder
4✔
40
            .Append("INSERT INTO ")
4✔
41
            .Append(table);
4✔
42

43
        if (insertStatement.ColumnExpressions?.Count > 0)
4!
44
        {
45
            insertBuilder
4✔
46
                .Append(" (")
4✔
47
                .AppendJoin(", ", insertStatement.ColumnExpressions.Select(ColumnExpression))
4✔
48
                .Append(")");
4✔
49
        }
50

51
        insertBuilder
4✔
52
            .AppendLine()
4✔
53
            .Append("VALUES ")
4✔
54
            .Append("(")
4✔
55
            .AppendJoin(", ", insertStatement.ValueExpressions)
4✔
56
            .Append(")");
4✔
57

58
        if (insertStatement.OutputExpressions?.Count > 0)
4!
59
        {
60
            insertBuilder
3✔
61
                .AppendLine()
3✔
62
                .Append("RETURNING ")
3✔
63
                .AppendJoin(", ", insertStatement.OutputExpressions.Select(ColumnExpression));
3✔
64
        }
65

66
        insertBuilder.AppendLine(";");
4✔
67

68
        return StringBuilderCache.ToString(insertBuilder);
4✔
69
    }
70

71
    /// <summary>
72
    /// Builds a SQL UPSERT statement for SQLite using ON CONFLICT syntax, including support for RETURNING and comments.
73
    /// </summary>
74
    /// <param name="upsertStatement">The <see cref="UpsertStatement"/> containing the UPSERT statement configuration.</param>
75
    /// <returns>A SQL UPSERT statement string for SQLite.</returns>
76
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="upsertStatement"/> is <c>null</c>.</exception>
77
    /// <exception cref="ArgumentException">Thrown if the table, values, keys, or update values are not specified.</exception>
78
    public override string BuildUpsert(UpsertStatement upsertStatement)
79
    {
80
        ValidateUpsert(upsertStatement);
8✔
81

82
        var upsertBuilder = StringBuilderCache.Acquire();
8✔
83

84
        if (upsertStatement.CommentExpressions?.Count > 0)
8!
85
        {
UNCOV
86
            upsertBuilder
×
87
                .AppendJoin(Environment.NewLine, upsertStatement.CommentExpressions)
×
88
                .AppendLine();
×
89
        }
90

91
        var table = TableExpression(upsertStatement.TableExpression);
8✔
92
        upsertBuilder
8✔
93
            .Append("INSERT INTO ")
8✔
94
            .Append(table)
8✔
95
            .Append(" (")
8✔
96
            .AppendJoin(", ", upsertStatement.ColumnExpressions.Select(ColumnExpression))
8✔
97
            .AppendLine(")")
8✔
98
            .Append("VALUES (")
8✔
99
            .AppendJoin(", ", upsertStatement.ValueExpressions)
8✔
100
            .AppendLine(")")
8✔
101
            .Append("ON CONFLICT (")
8✔
102
            .AppendJoin(", ", upsertStatement.KeyExpressions.Select(ColumnExpression))
8✔
103
            .AppendLine(") DO UPDATE")
8✔
104
            .Append("SET ")
8✔
105
            .AppendJoin(", ", upsertStatement.UpdateExpressions.Select(u => $"{ColumnExpression(u)} = EXCLUDED.{ColumnExpression(u)}"));
8✔
106

107
        if (upsertStatement.OutputExpressions?.Count > 0)
8!
108
        {
109
            upsertBuilder
3✔
110
                .AppendLine()
3✔
111
                .Append("RETURNING ")
3✔
112
                .AppendJoin(", ", upsertStatement.OutputExpressions.Select(ColumnExpression));
3✔
113
        }
114

115
        upsertBuilder.AppendLine(";");
8✔
116

117
        return StringBuilderCache.ToString(upsertBuilder);
8✔
118
    }
119

120
    /// <summary>
121
    /// Builds a SQL UPDATE statement for SQLite, including support for FROM, JOIN, WHERE, RETURNING, and comments.
122
    /// </summary>
123
    /// <param name="updateStatement">The <see cref="UpdateStatement"/> containing the UPDATE statement configuration.</param>
124
    /// <returns>A SQL UPDATE statement string for SQLite.</returns>
125
    /// <exception cref="ArgumentException">Thrown if the table or update values are not specified.</exception>
126
    public override string BuildUpdate(UpdateStatement updateStatement)
127
    {
128
        if (updateStatement.UpdateExpressions == null || updateStatement.UpdateExpressions.Count == 0)
2!
UNCOV
129
            throw new ArgumentException("No values specified for update", nameof(updateStatement));
×
130

131
        var updateBuilder = StringBuilderCache.Acquire();
2✔
132

133
        if (updateStatement.CommentExpressions?.Count > 0)
2!
134
        {
135
            updateBuilder
1✔
136
                .AppendJoin(Environment.NewLine, updateStatement.CommentExpressions)
1✔
137
                .AppendLine();
1✔
138
        }
139

140
        var table = TableExpression(updateStatement.TableExpression);
2✔
141

142
        updateBuilder
2✔
143
            .Append("UPDATE ")
2✔
144
            .Append(table)
2✔
145
            .AppendLine()
2✔
146
            .Append("SET ")
2✔
147
            .AppendJoin(", ", updateStatement.UpdateExpressions.Select(UpdateExpression));
2✔
148

149
        if (updateStatement.FromExpressions?.Count > 0)
2!
150
        {
UNCOV
151
            updateBuilder
×
152
                .AppendLine()
×
153
                .Append("FROM ")
×
154
                .AppendJoin(", ", updateStatement.FromExpressions.Select(TableExpression));
×
155
        }
156

157
        if (updateStatement.JoinExpressions?.Count > 0)
2!
158
        {
UNCOV
159
            foreach (var joinExpression in updateStatement.JoinExpressions)
×
160
            {
UNCOV
161
                updateBuilder
×
162
                    .AppendLine()
×
163
                    .Append(JoinExpression(joinExpression));
×
164
            }
165
        }
166

167
        if (updateStatement.WhereExpressions?.Count > 0)
2!
168
        {
169
            updateBuilder
2✔
170
                .AppendLine()
2✔
171
                .Append("WHERE ")
2✔
172
                .Append("(")
2✔
173
                .AppendJoin(" AND ", updateStatement.WhereExpressions.Select(WhereExpression))
2✔
174
                .Append(")");
2✔
175
        }
176

177
        if (updateStatement.OutputExpressions?.Count > 0)
2!
178
        {
179
            updateBuilder
1✔
180
                .AppendLine()
1✔
181
                .Append("RETURNING ")
1✔
182
                .AppendJoin(", ", updateStatement.OutputExpressions.Select(ColumnExpression));
1✔
183
        }
184

185
        updateBuilder.AppendLine(";");
2✔
186

187
        return StringBuilderCache.ToString(updateBuilder);
2✔
188
    }
189

190
    /// <summary>
191
    /// Builds a SQL DELETE statement for SQLite, including support for FROM, JOIN, WHERE, RETURNING, and comments.
192
    /// </summary>
193
    /// <param name="deleteStatement">The <see cref="DeleteStatement"/> containing the DELETE statement configuration.</param>
194
    /// <returns>A SQL DELETE statement string for SQLite.</returns>
195
    /// <exception cref="ArgumentException">Thrown if the table is not specified.</exception>
196
    public override string BuildDelete(DeleteStatement deleteStatement)
197
    {
198
        if (deleteStatement.TableExpression == null)
1!
UNCOV
199
            throw new ArgumentException("No table specified to delete from", nameof(deleteStatement));
×
200

201
        var deleteBuilder = StringBuilderCache.Acquire();
1✔
202

203
        if (deleteStatement.CommentExpressions?.Count > 0)
1!
204
        {
205
            deleteBuilder
1✔
206
                .AppendJoin(Environment.NewLine, deleteStatement.CommentExpressions)
1✔
207
                .AppendLine();
1✔
208
        }
209

210
        var table = TableExpression(deleteStatement.TableExpression);
1✔
211

212
        deleteBuilder
1✔
213
            .Append("DELETE FROM ")
1✔
214
            .Append(table);
1✔
215

216
        if (deleteStatement.FromExpressions?.Count > 0)
1!
217
        {
UNCOV
218
            deleteBuilder
×
219
                .AppendLine()
×
220
                .Append("FROM ")
×
221
                .AppendJoin(", ", deleteStatement.FromExpressions.Select(TableExpression));
×
222
        }
223

224
        if (deleteStatement.JoinExpressions?.Count > 0)
1!
225
        {
UNCOV
226
            foreach (var joinExpression in deleteStatement.JoinExpressions)
×
227
            {
UNCOV
228
                deleteBuilder
×
229
                    .AppendLine()
×
230
                    .Append(JoinExpression(joinExpression));
×
231
            }
232
        }
233

234
        if (deleteStatement.WhereExpressions?.Count > 0)
1!
235
        {
236
            deleteBuilder
1✔
237
                .AppendLine()
1✔
238
                .Append("WHERE ")
1✔
239
                .Append("(")
1✔
240
                .AppendJoin(" AND ", deleteStatement.WhereExpressions.Select(WhereExpression))
1✔
241
                .Append(")");
1✔
242
        }
243

244
        if (deleteStatement.OutputExpressions?.Count > 0)
1!
245
        {
246
            deleteBuilder
1✔
247
                .AppendLine()
1✔
248
                .Append("RETURNING ")
1✔
249
                .AppendJoin(", ", deleteStatement.OutputExpressions.Select(ColumnExpression));
1✔
250
        }
251

252
        deleteBuilder.AppendLine(";");
1✔
253

254
        return StringBuilderCache.ToString(deleteBuilder);
1✔
255
    }
256

257
    /// <summary>
258
    /// Builds a SQL table expression for SQLite, omitting schema (SQLite does not support schema in the same way as SQL Server).
259
    /// </summary>
260
    /// <param name="tableExpression">The <see cref="TableExpression"/> representing the table.</param>
261
    /// <returns>A SQL table expression string for SQLite.</returns>
262
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="tableExpression"/> is <c>null</c>.</exception>
263
    public override string TableExpression(TableExpression tableExpression)
264
    {
265
        ArgumentNullException.ThrowIfNull(tableExpression);
26✔
266

267
        // sqlite doesn't support schema
268
        tableExpression = tableExpression with { TableSchema = null };
26✔
269

270
        return base.TableExpression(tableExpression);
26✔
271
    }
272

273
    /// <summary>
274
    /// Builds a SQL LIMIT/OFFSET expression for SQLite.
275
    /// </summary>
276
    /// <param name="limitExpression">The <see cref="LimitExpression"/> representing the limit and offset.</param>
277
    /// <returns>A SQL LIMIT/OFFSET expression string for SQLite, or an empty string if not applicable.</returns>
278
    public override string LimitExpression(LimitExpression limitExpression)
279
    {
280
        if (limitExpression is null || limitExpression.Size == 0)
4!
UNCOV
281
            return string.Empty;
×
282

283
        return $"LIMIT {limitExpression.Size} OFFSET {limitExpression.Offset}";
4✔
284
    }
285

286
    /// <summary>
287
    /// Quotes an identifier (such as a table or column name) for SQLite, using double quotes.
288
    /// </summary>
289
    /// <param name="name">The identifier to quote.</param>
290
    /// <returns>The quoted identifier, or the original name if quoting is not required.</returns>
291
    public override string QuoteIdentifier(string name)
292
    {
293
        if (name.IsNullOrWhiteSpace())
269!
UNCOV
294
            return string.Empty;
×
295

296
        if (name == "*")
269✔
297
            return name;
1✔
298

299
        if (name.StartsWith("\"") && name.EndsWith("\""))
268!
UNCOV
300
            return name;
×
301

302
        return "\"" + name.Replace("\"", "\"\"") + "\"";
268✔
303
    }
304

305
    /// <summary>
306
    /// Parses a quoted identifier and returns the unquoted name for SQLite.
307
    /// </summary>
308
    /// <param name="name">The quoted identifier.</param>
309
    /// <returns>The unquoted identifier name.</returns>
310
    public override string ParseIdentifier(string name)
311
    {
UNCOV
312
        if (name.StartsWith("\"") && name.EndsWith("\""))
×
UNCOV
313
            return name.Substring(1, name.Length - 2);
×
314

315
        return name;
×
316
    }
317
}
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