• 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

67.77
/src/FluentCommand/ListDataReader.cs
1
using System.Collections;
2
using System.Data;
3
using System.Data.Common;
4

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

8
namespace FluentCommand;
9

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

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

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

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

39
        _iterator = list.GetEnumerator();
28✔
40

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

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

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

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

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

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

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

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

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

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

104
        return table;
2✔
105
    }
106

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

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

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

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

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

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

148
        _disposed = true;
24✔
149
        base.Dispose(disposing);
24✔
150
    }
24✔
151

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

155
    /// <inheritdoc/>
UNCOV
156
    public override string GetDataTypeName(int i) => _activeColumns[i].MemberType.Name;
×
157

158
    /// <inheritdoc/>
159
    public override Type GetFieldType(int i) => _activeColumns[i].MemberType;
2,497✔
160

161
    /// <inheritdoc/>
162
    public override object GetValue(int i) => _activeColumns[i].GetValue(_iterator.Current)!;
11,015✔
163

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

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

179
        return -1;
3✔
180
    }
181

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

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

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

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

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

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

UNCOV
202
        return count;
×
203
    }
204

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

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

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

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

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

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

223
        return count;
×
224
    }
225

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

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

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

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

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

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

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

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

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

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

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

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

266
    /// <inheritdoc/>
267
    public override object this[string name] => GetValue(GetOrdinal(name));
2✔
268
}
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