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

loresoft / FluentCommand / 9074741070

14 May 2024 06:23AM UTC coverage: 54.074% (+0.4%) from 53.649%
9074741070

push

github

pwelter34
Update DataMergeGeneratorTests.BuildTableSqlTest.verified.txt

1186 of 2873 branches covered (41.28%)

Branch coverage included in aggregate %.

3732 of 6222 relevant lines covered (59.98%)

716.09 hits per line

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

64.63
/src/FluentCommand.Csv/CsvCommandExtensions.cs
1
using System.Buffers;
2
using System.Data;
3
using System.Data.Common;
4
using System.Globalization;
5
using System.Text;
6

7
using CsvHelper;
8
using CsvHelper.Configuration;
9

10
using FluentCommand.Extensions;
11

12
using Microsoft.IO;
13

14
namespace FluentCommand;
15

16
public static class CsvCommandExtensions
17
{
18
    private static readonly RecyclableMemoryStreamManager _memoryStreamManager = new();
3✔
19

20
    /// <summary>
21
    /// Executes the query and returns a CSV string from data set returned by the query.
22
    /// </summary>
23
    /// <param name="dataCommand">The data command.</param>
24
    /// <param name="csvConfiguration">The configuration used for the CSV writer</param>
25
    /// <returns>
26
    /// A CSV string representing the <see cref="IDataReader" /> result of the command.
27
    /// </returns>
28
    public static string QueryCsv(this IDataCommand dataCommand, CsvConfiguration csvConfiguration = default)
29
    {
30
        if (dataCommand is null)
3!
31
            throw new ArgumentNullException(nameof(dataCommand));
×
32

33
        using var stream = _memoryStreamManager.GetStream();
3✔
34

35
        QueryCsv(dataCommand, stream, csvConfiguration);
3✔
36

37
        var bytes = stream.GetReadOnlySequence();
3✔
38

39
#if NET5_0_OR_GREATER
40
        return Encoding.UTF8.GetString(bytes);
3✔
41
#else
42
        return Encoding.UTF8.GetString(bytes.ToArray());
43
#endif
44
    }
3✔
45

46
    /// <summary>
47
    /// Executes the query and writes the CSV data to the specified <paramref name="stream"/>.
48
    /// </summary>
49
    /// <param name="dataCommand">The data command.</param>
50
    /// <param name="stream">The stream writer.</param>
51
    /// <param name="csvConfiguration">The configuration used for the CSV writer</param>
52
    public static void QueryCsv(this IDataCommand dataCommand, Stream stream, CsvConfiguration csvConfiguration = default)
53
    {
54
        if (dataCommand is null)
6!
55
            throw new ArgumentNullException(nameof(dataCommand));
×
56
        if (stream is null)
6!
57
            throw new ArgumentNullException(nameof(stream));
×
58

59
        if (csvConfiguration == null)
6✔
60
            csvConfiguration = new CsvConfiguration(CultureInfo.InvariantCulture) { HasHeaderRecord = true };
6✔
61

62
        using var streamWriter = new StreamWriter(stream, Encoding.UTF8, 1024, true);
6✔
63
        using var csvWriter = new CsvWriter(streamWriter, csvConfiguration, true);
6✔
64

65
        dataCommand.Read(reader => WriteData(reader, csvWriter), CommandBehavior.SequentialAccess | CommandBehavior.SingleResult);
12✔
66

67
        csvWriter.Flush();
6✔
68
        streamWriter.Flush();
6✔
69
    }
12✔
70

71

72
    /// <summary>
73
    /// Executes the query and returns a CSV string from data set returned by the query asynchronously.
74
    /// </summary>
75
    /// <param name="dataCommand">The data command.</param>
76
    /// <param name="csvConfiguration">The configuration used for the CSV writer</param>
77
    /// <param name="cancellationToken">The cancellation token.</param>
78
    /// <returns>
79
    /// A CSV string representing the <see cref="IDataReader" /> result of the command.
80
    /// </returns>
81
    public static async Task<string> QueryCsvAsync(this IDataCommand dataCommand, CsvConfiguration csvConfiguration = default, CancellationToken cancellationToken = default)
82
    {
83
        if (dataCommand is null)
6!
84
            throw new ArgumentNullException(nameof(dataCommand));
×
85

86
        using var stream = _memoryStreamManager.GetStream();
6✔
87

88
        await QueryCsvAsync(dataCommand, stream, csvConfiguration, cancellationToken);
6✔
89

90
        var bytes = stream.GetReadOnlySequence();
6✔
91

92
#if NET5_0_OR_GREATER
93
        return Encoding.UTF8.GetString(bytes);
6✔
94
#else
95
        return Encoding.UTF8.GetString(bytes.ToArray());
96
#endif
97
    }
6✔
98

99
    /// <summary>
100
    /// Executes the query and writes the CSV data to the specified <paramref name="stream"/>.
101
    /// </summary>
102
    /// <param name="dataCommand">The data command.</param>
103
    /// <param name="stream">The stream writer.</param>
104
    /// <param name="csvConfiguration">The configuration used for the CSV writer</param>
105
    /// <param name="cancellationToken">The cancellation token.</param>
106
    /// <returns>
107
    /// A CSV string representing the <see cref="IDataReader" /> result of the command.
108
    /// </returns>
109
    public static async Task QueryCsvAsync(this IDataCommand dataCommand, Stream stream, CsvConfiguration csvConfiguration = default, CancellationToken cancellationToken = default)
110
    {
111
        if (dataCommand is null)
9!
112
            throw new ArgumentNullException(nameof(dataCommand));
×
113
        if (stream is null)
9!
114
            throw new ArgumentNullException(nameof(stream));
×
115

116
        if (csvConfiguration == null)
9✔
117
            csvConfiguration = new CsvConfiguration(CultureInfo.InvariantCulture) { HasHeaderRecord = true };
9✔
118

119
        using var streamWriter = new StreamWriter(stream, Encoding.UTF8, 1024, true);
9✔
120
        await using var csvWriter = new CsvWriter(streamWriter, csvConfiguration, true);
9✔
121

122
        await dataCommand.ReadAsync(async (reader, token) =>
9✔
123
        {
9✔
124
            if (reader is DbDataReader dataReader)
9!
125
                await WriteDataAsync(dataReader, csvWriter, token);
9✔
126
            else
9✔
127
                WriteData(reader, csvWriter);
×
128

9✔
129
        }, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, cancellationToken);
18✔
130

131
        await csvWriter.FlushAsync();
9✔
132
        await streamWriter.FlushAsync();
9✔
133
    }
9✔
134

135

136
    private static void WriteData(IDataReader reader, CsvWriter writer)
137
    {
138
        // if config says to include header, default false
139
        var wroteHeader = !writer.Configuration.HasHeaderRecord;
6✔
140

141
        while (reader.Read())
42✔
142
        {
143
            if (!wroteHeader)
36✔
144
            {
145
                WriteHeader(reader, writer);
6✔
146
                wroteHeader = true;
6✔
147
            }
148

149
            WriteRow(reader, writer);
36✔
150
        }
151
    }
6✔
152

153
    private static async Task WriteDataAsync(DbDataReader reader, CsvWriter writer, CancellationToken cancellationToken = default)
154
    {
155
        // if config says to include header, default false
156
        var wroteHeader = !writer.Configuration.HasHeaderRecord;
9✔
157

158
        while (await reader.ReadAsync(cancellationToken))
63✔
159
        {
160
            if (!wroteHeader)
54✔
161
            {
162
                WriteHeader(reader, writer);
9✔
163
                wroteHeader = true;
9✔
164
            }
165

166
            WriteRow(reader, writer);
54✔
167
        }
168
    }
9✔
169

170
    private static void WriteHeader(IDataReader reader, CsvWriter writer)
171
    {
172
        for (int index = 0; index < reader.FieldCount; index++)
546✔
173
        {
174
            var name = reader.GetName(index);
258✔
175
            writer.WriteField(name);
258✔
176
        }
177
        writer.NextRecord();
15✔
178
    }
15✔
179

180
    private static void WriteRow(IDataReader reader, CsvWriter writer)
181
    {
182
        for (int index = 0; index < reader.FieldCount; index++)
3,276✔
183
        {
184
            WriteValue(reader, writer, index);
1,548✔
185
        }
186
        writer.NextRecord();
90✔
187
    }
90✔
188

189
    private static void WriteValue(IDataReader reader, CsvWriter writer, int index)
190
    {
191
        if (reader.IsDBNull(index))
1,548✔
192
        {
193
            writer.WriteField(string.Empty);
684✔
194
            return;
684✔
195
        }
196

197
        var type = reader.GetFieldType(index);
864✔
198

199
        if (type == typeof(string))
864✔
200
        {
201
            var value = reader.GetString(index);
180✔
202
            writer.WriteField(value);
180✔
203
            return;
180✔
204
        }
205

206
        if (type == typeof(bool))
684✔
207
        {
208
            var value = reader.GetBoolean(index);
234✔
209
            writer.WriteField(value);
234✔
210
            return;
234✔
211
        }
212

213
        if (type == typeof(byte))
450!
214
        {
215
            var value = reader.GetByte(index);
×
216
            writer.WriteField(value);
×
217
            return;
×
218
        }
219

220
        if (type == typeof(short))
450!
221
        {
222
            var value = reader.GetInt16(index);
×
223
            writer.WriteField(value);
×
224
            return;
×
225
        }
226

227
        if (type == typeof(int))
450✔
228
        {
229
            var value = reader.GetInt32(index);
108✔
230
            writer.WriteField(value);
108✔
231
            return;
108✔
232
        }
233

234
        if (type == typeof(long))
342!
235
        {
236
            var value = reader.GetInt64(index);
×
237
            writer.WriteField(value);
×
238
            return;
×
239
        }
240

241
        if (type == typeof(float))
342!
242
        {
243
            var value = reader.GetFloat(index);
×
244
            writer.WriteField(value);
×
245
            return;
×
246
        }
247

248
        if (type == typeof(double))
342!
249
        {
250
            var value = reader.GetDouble(index);
×
251
            writer.WriteField(value);
×
252
            return;
×
253
        }
254

255
        if (type == typeof(decimal))
342!
256
        {
257
            var value = reader.GetDecimal(index);
×
258
            writer.WriteField(value);
×
259
            return;
×
260
        }
261

262
#if NET6_0_OR_GREATER
263
        if (type == typeof(DateOnly))
342!
264
        {
265
            var value = reader.GetValue<DateOnly>(index);
×
266
            var formatted = value.ToString("yyyy'-'MM'-'dd", CultureInfo.InvariantCulture);
×
267

268
            writer.WriteField(formatted);
×
269
            return;
×
270
        }
271

272
        if (type == typeof(TimeOnly))
342!
273
        {
274
            var value = reader.GetValue<TimeOnly>(index);
×
275
            string formatted = value.Second == 0 && value.Millisecond == 0
×
276
                ? value.ToString("HH':'mm", CultureInfo.InvariantCulture)
×
277
                : value.ToString(CultureInfo.InvariantCulture);
×
278

279
            writer.WriteField(formatted);
×
280
            return;
×
281
        }
282
#endif
283

284
        if (type == typeof(TimeSpan))
342!
285
        {
286
            var value = reader.GetValue<TimeSpan>(index);
×
287
            string formatted = value.Seconds == 0 && value.Milliseconds == 0
×
288
                ? value.ToString(@"hh\:mm", CultureInfo.InvariantCulture)
×
289
                : value.ToString();
×
290

291
            writer.WriteField(formatted);
×
292
            return;
×
293
        }
294

295
        if (type == typeof(DateTime))
342!
296
        {
297
            var value = reader.GetDateTime(index);
×
298
            var dataType = reader.GetDataTypeName(index).ToLowerInvariant();
×
299

300
            if (string.Equals(dataType, "date", StringComparison.OrdinalIgnoreCase))
×
301
            {
302
                var formattedDate = value.ToString("yyyy'-'MM'-'dd", CultureInfo.InvariantCulture);
×
303
                writer.WriteField(formattedDate);
×
304
            }
305
            else
306
            {
307
                writer.WriteField(value);
×
308
            }
309
            return;
×
310
        }
311

312
        if (type == typeof(DateTimeOffset))
342✔
313
        {
314
            var value = reader.GetValue(index);
180✔
315
            if (value is DateTimeOffset offset)
180!
316
            {
317
                writer.WriteField(offset);
180✔
318
                return;
180✔
319
            }
320

321
            var date = reader.GetDateTime(index);
×
322
            date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
×
323

324
            offset = new DateTimeOffset(date, TimeSpan.Zero);
×
325

326
            writer.WriteField(offset);
×
327
            return;
×
328
        }
329

330
        if (type == typeof(Guid))
162✔
331
        {
332
            var value = reader.GetGuid(index);
72✔
333
            writer.WriteField(value);
72✔
334
            return;
72✔
335
        }
336

337
        // fallback
338
        var v = reader.GetValue(index);
90✔
339
        writer.WriteField(v.ToString());
90✔
340
    }
90✔
341

342
}
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