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

loresoft / FluentCommand / 8850661434

26 Apr 2024 03:30PM UTC coverage: 54.48% (+2.6%) from 51.881%
8850661434

push

github

pwelter34
update debug settings

1152 of 2717 branches covered (42.4%)

Branch coverage included in aggregate %.

3682 of 6156 relevant lines covered (59.81%)

701.76 hits per line

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

73.47
/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 Microsoft.IO;
11

12
namespace FluentCommand;
13

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

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

31
        using var stream = _memoryStreamManager.GetStream();
3✔
32

33
        QueryCsv(dataCommand, stream, csvConfiguration);
3✔
34

35
        var bytes = stream.GetReadOnlySequence();
3✔
36

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

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

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

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

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

65
        csvWriter.Flush();
6✔
66
        streamWriter.Flush();
6✔
67
    }
12✔
68

69

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

84
        using var stream = _memoryStreamManager.GetStream();
6✔
85

86
        await QueryCsvAsync(dataCommand, stream, csvConfiguration, cancellationToken);
6✔
87

88
        var bytes = stream.GetReadOnlySequence();
6✔
89

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

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

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

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

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

9✔
127
        }, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, cancellationToken);
18✔
128

129
        await csvWriter.FlushAsync();
9✔
130
        await streamWriter.FlushAsync();
9✔
131
    }
9✔
132

133

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

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

147
            WriteRow(reader, writer);
36✔
148
        }
149
    }
6✔
150

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

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

164
            WriteRow(reader, writer);
54✔
165
        }
166
    }
9✔
167

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

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

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

195
        var type = reader.GetFieldType(index);
864✔
196

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

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

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

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

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

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

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

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

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

260
        if (type == typeof(TimeSpan))
342!
261
        {
262
            var value = reader.GetDateTime(index);
×
263
            writer.WriteField(value);
×
264
            return;
×
265
        }
266

267
        if (type == typeof(DateTime))
342!
268
        {
269
            var value = reader.GetDateTime(index);
×
270
            writer.WriteField(value);
×
271
            return;
×
272
        }
273

274
        if (type == typeof(DateTimeOffset))
342✔
275
        {
276
            var value = reader.GetValue(index);
180✔
277
            if (value is DateTimeOffset offset)
180!
278
            {
279
                writer.WriteField(offset);
180✔
280
                return;
180✔
281
            }
282

283
            var date = reader.GetDateTime(index);
×
284
            date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
×
285

286
            offset = new DateTimeOffset(date, TimeSpan.Zero);
×
287

288
            writer.WriteField(offset);
×
289
            return;
×
290
        }
291

292
        if (type == typeof(Guid))
162✔
293
        {
294
            var value = reader.GetGuid(index);
72✔
295
            writer.WriteField(value);
72✔
296
            return;
72✔
297
        }
298

299
        // fallback
300
        var v = reader.GetValue(index);
90✔
301
        writer.WriteField(v.ToString());
90✔
302
    }
90✔
303

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