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

loresoft / FluentCommand / 29168809467

11 Jul 2026 09:26PM UTC coverage: 65.067% (+0.02%) from 65.051%
29168809467

push

github

pwelter34
update packages

1745 of 3480 branches covered (50.14%)

Branch coverage included in aggregate %.

5549 of 7730 relevant lines covered (71.79%)

302.92 hits per line

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

71.32
/src/FluentCommand/ListDataReader.cs
1
using System.Collections;
2
using System.Data;
3
using System.Data.Common;
4
using System.Text.Json;
5

6
using FluentCommand.Extensions;
7
using FluentCommand.Reflection;
8

9
namespace FluentCommand;
10

11
/// <summary>
12
/// Read a list of items using a <see cref="DbDataReader"/>
13
/// </summary>
14
/// <typeparam name="T">The type of items being read</typeparam>
15
public class ListDataReader<T> : DbDataReader where T : class
16
{
17
    // ReSharper disable once StaticMemberInGenericType
18
    private static readonly TypeAccessor _typeAccessor;
19

20
    private readonly IEnumerator<T> _iterator;
21
    private readonly List<IMemberAccessor> _activeColumns;
22
    private readonly Dictionary<string, int> _columnOrdinals;
23
    private bool _closed;
24
    private bool _disposed;
25

26
    static ListDataReader()
27
    {
28
        _typeAccessor = TypeAccessor.GetAccessor<T>();
8✔
29
    }
8✔
30

31
    /// <summary>
32
    /// Initializes a new instance of the <see cref="ListDataReader{T}"/> class.
33
    /// </summary>
34
    /// <param name="list">The list of items to read</param>
35
    /// <param name="ignoreNames">A list of property names to ignore in the reader</param>
36
    public ListDataReader(IEnumerable<T> list, IEnumerable<string>? ignoreNames = null)
35✔
37
    {
38
        ArgumentNullException.ThrowIfNull(list);
35✔
39

40
        _iterator = list.GetEnumerator();
34✔
41

42
        var ignored = new HashSet<string>(ignoreNames ?? []);
34✔
43

44
        _activeColumns = _typeAccessor
34✔
45
            .GetProperties()
34✔
46
            .Where(c => !ignored.Contains(c.Name))
34✔
47
            .ToList();
34✔
48

49
        _columnOrdinals = _activeColumns
34✔
50
            .Select((col, idx) => new { col.Column, idx })
34✔
51
            .ToDictionary(x => x.Column, x => x.idx, StringComparer.OrdinalIgnoreCase);
34✔
52
    }
34✔
53

54
    /// <summary>
55
    /// Gets a value indicating the depth of nesting for the current row. Always returns 0.
56
    /// </summary>
57
    public override int Depth => 0;
×
58

59
    /// <summary>
60
    /// Gets a value indicating whether the data reader is closed.
61
    /// </summary>
62
    public override bool IsClosed => _closed;
3✔
63

64
    /// <summary>
65
    /// Gets the number of rows affected. Always returns 0.
66
    /// </summary>
67
    public override int RecordsAffected => 0;
×
68

69
    /// <summary>
70
    /// Gets a value indicating whether the reader has rows. Always returns false.
71
    /// </summary>
72
    public override bool HasRows => false;
×
73

74
    /// <summary>
75
    /// Returns a <see cref="DataTable"/> that describes the column metadata of the data reader.
76
    /// </summary>
77
    /// <returns>A <see cref="DataTable"/> describing the column metadata.</returns>
78
    public override DataTable GetSchemaTable()
79
    {
80
        // these are the columns used by DataTable load
81
        var table = new DataTable
2✔
82
        {
2✔
83
            Columns =
2✔
84
            {
2✔
85
                {"ColumnOrdinal", typeof(int)},
2✔
86
                {"ColumnName", typeof(string)},
2✔
87
                {"DataType", typeof(Type)},
2✔
88
                {"ColumnSize", typeof(int)},
2✔
89
                {"AllowDBNull", typeof(bool)}
2✔
90
            }
2✔
91
        };
2✔
92

93
        for (int i = 0; i < _activeColumns.Count; i++)
14✔
94
        {
95
            var rowData = new object[5];
5✔
96
            rowData[0] = i;
5✔
97
            rowData[1] = _activeColumns[i].Column;
5✔
98
            rowData[2] = GetFieldType(_activeColumns[i]);
5✔
99
            rowData[3] = -1;
5✔
100
            rowData[4] = _activeColumns[i].MemberType.IsNullable();
5✔
101

102
            table.Rows.Add(rowData);
5✔
103
        }
104

105
        return table;
2✔
106
    }
107

108
    /// <summary>
109
    /// Advances the data reader to the next result. Always returns false.
110
    /// </summary>
111
    /// <returns>false, as multiple result sets are not supported.</returns>
112
    public override bool NextResult() => false;
1✔
113

114
    /// <summary>
115
    /// Advances the data reader to the next record.
116
    /// </summary>
117
    /// <returns>true if there are more rows; otherwise, false.</returns>
118
    public override bool Read() => _iterator.MoveNext();
1,144✔
119

120
    /// <summary>
121
    /// Returns an enumerator that iterates through the rows of the data reader.
122
    /// </summary>
123
    /// <returns>An <see cref="IEnumerator"/> for the data reader.</returns>
124
    public override IEnumerator GetEnumerator() => new DbEnumerator(this);
×
125

126
    /// <summary>
127
    /// Closes the data reader and releases resources.
128
    /// </summary>
129
    public override void Close()
130
    {
131
        Dispose(true);
30✔
132
    }
30✔
133

134
    /// <summary>
135
    /// Releases the unmanaged resources used by the ListDataReader and optionally releases the managed resources.
136
    /// </summary>
137
    /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
138
    protected override void Dispose(bool disposing)
139
    {
140
        if (_disposed)
58✔
141
            return;
29✔
142

143
        if (disposing)
29!
144
        {
145
            _iterator.Dispose();
29✔
146
            _closed = true;
29✔
147
        }
148

149
        _disposed = true;
29✔
150
        base.Dispose(disposing);
29✔
151
    }
29✔
152

153
    /// <inheritdoc/>
154
    public override string GetName(int i) => _activeColumns[i].Column;
2,545✔
155

156
    /// <inheritdoc/>
157
    public override string GetDataTypeName(int i) => GetFieldType(i).Name;
×
158

159
    /// <inheritdoc/>
160
    public override Type GetFieldType(int i) => GetFieldType(_activeColumns[i]);
2,500✔
161

162
    /// <inheritdoc/>
163
    public override object GetValue(int i) => GetValue(_activeColumns[i]);
11,025✔
164

165
    /// <inheritdoc/>
166
    public override int GetValues(object[] values)
167
    {
168
        int count = Math.Min(_activeColumns.Count, values.Length);
2✔
169
        for (int i = 0; i < count; i++)
12✔
170
            values[i] = GetValue(i);
4✔
171
        return count;
2✔
172
    }
173

174
    /// <inheritdoc/>
175
    public override int GetOrdinal(string name)
176
    {
177
        if (_columnOrdinals.TryGetValue(name, out int ordinal))
106✔
178
            return ordinal;
103✔
179

180
        return -1;
3✔
181
    }
182

183
    /// <inheritdoc/>
184
    public override bool GetBoolean(int i) => (bool)GetValue(i);
×
185

186
    /// <inheritdoc/>
187
    public override byte GetByte(int i) => (byte)GetValue(i);
×
188

189
    /// <inheritdoc/>
190
    public override long GetBytes(int i, long fieldOffset, byte[]? buffer, int bufferOffset, int length)
191
    {
192
        byte[] value = (byte[])GetValue(i);
×
193

194
        int available = value.Length - (int)fieldOffset;
×
195
        if (available <= 0)
×
196
            return 0;
×
197

198
        int count = Math.Min(length, available);
×
199

200
        if (buffer != null)
×
201
            Buffer.BlockCopy(value, (int)fieldOffset, buffer, bufferOffset, count);
×
202

203
        return count;
×
204
    }
205

206
    /// <inheritdoc/>
207
    public override char GetChar(int i) => (char)GetValue(i);
×
208

209
    /// <inheritdoc/>
210
    public override long GetChars(int i, long fieldOffset, char[]? buffer, int bufferOffset, int length)
211
    {
212
        ArgumentNullException.ThrowIfNull(buffer);
×
213

214
        string value = (string)GetValue(i);
×
215

216
        int available = value.Length - (int)fieldOffset;
×
217
        if (available <= 0)
×
218
            return 0;
×
219

220
        int count = Math.Min(length, available);
×
221

222
        value.CopyTo((int)fieldOffset, buffer, bufferOffset, count);
×
223

224
        return count;
×
225
    }
226

227
    /// <inheritdoc/>
228
    public override Guid GetGuid(int i) => (Guid)GetValue(i);
×
229

230
    /// <inheritdoc/>
231
    public override short GetInt16(int i) => (short)GetValue(i);
×
232

233
    /// <inheritdoc/>
234
    public override int GetInt32(int i) => (int)GetValue(i);
4✔
235

236
    /// <inheritdoc/>
237
    public override long GetInt64(int i) => (long)GetValue(i);
×
238

239
    /// <inheritdoc/>
240
    public override float GetFloat(int i) => (float)GetValue(i);
×
241

242
    /// <inheritdoc/>
243
    public override double GetDouble(int i) => (double)GetValue(i);
×
244

245
    /// <inheritdoc/>
246
    public override string GetString(int i) => (string)GetValue(i);
7✔
247

248
    /// <inheritdoc/>
249
    public override decimal GetDecimal(int i) => (decimal)GetValue(i);
×
250

251
    /// <inheritdoc/>
252
    public override DateTime GetDateTime(int i) => (DateTime)GetValue(i);
2✔
253

254
    /// <inheritdoc/>
255
    public override bool IsDBNull(int i)
256
    {
257
        var value = GetValue(i);
5✔
258
        return value == null || value == DBNull.Value;
5✔
259
    }
260

261
    /// <inheritdoc/>
262
    public override int FieldCount => _activeColumns.Count;
2,967✔
263

264
    /// <inheritdoc/>
265
    public override object this[int i] => GetValue(i);
×
266

267
    /// <inheritdoc/>
268
    public override object this[string name] => GetValue(GetOrdinal(name));
2✔
269

270

271
    private static Type GetFieldType(IMemberAccessor column)
272
    {
273
        var memberType = column.MemberType.GetUnderlyingType();
2,505✔
274
        return memberType == typeof(JsonElement) ? typeof(string) : column.MemberType;
2,505✔
275
    }
276

277
    private object GetValue(IMemberAccessor column)
278
    {
279
        var value = column.GetValue(_iterator.Current);
11,025✔
280
        return value is JsonElement jsonElement
11,025✔
281
            ? GetJsonValue(jsonElement)!
11,025✔
282
            : value!;
11,025✔
283
    }
284

285
    private static string? GetJsonValue(JsonElement jsonElement)
286
    {
287
        return jsonElement.ValueKind != JsonValueKind.Undefined
2!
288
            ? jsonElement.GetRawText()
2✔
289
            : null;
2✔
290
    }
291
}
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