Skip to content

Commit 7782058

Browse files
author
electricessence
committed
Tweaks and micro optimizations.
1 parent b0d353b commit 7782058

3 files changed

Lines changed: 52 additions & 40 deletions

File tree

Extensions.cs

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -233,17 +233,12 @@ public static IEnumerable<object[]> AsEnumerable(this IDataReader reader)
233233
}
234234
}
235235

236-
/// <summary>
237-
/// Enumerates all the remaining values of the current result set of a data reader.
238-
/// </summary>
239-
/// <param name="reader">The reader to enumerate.</param>
240-
/// <param name="ordinals">The limited set of ordinals to include. If none are specified, the returned objects will be empty.</param>
241-
/// <returns>An enumeration of the values returned from a data reader.</returns>
242-
public static IEnumerable<object[]> AsEnumerable(this IDataReader reader, IEnumerable<int> ordinals)
236+
237+
static IEnumerable<object[]> AsEnumerableInternal(this IDataReader reader, IEnumerable<int> ordinals, bool readStarted)
243238
{
244-
if (reader.Read())
239+
if (readStarted || reader.Read())
245240
{
246-
var o = ordinals.ToArray();
241+
var o = ordinals as int[] ?? ordinals.ToArray();
247242
var fieldCount = o.Length;
248243
if (fieldCount == 0)
249244
{
@@ -266,6 +261,15 @@ public static IEnumerable<object[]> AsEnumerable(this IDataReader reader, IEnume
266261
}
267262
}
268263

264+
/// <summary>
265+
/// Enumerates all the remaining values of the current result set of a data reader.
266+
/// </summary>
267+
/// <param name="reader">The reader to enumerate.</param>
268+
/// <param name="ordinals">The limited set of ordinals to include. If none are specified, the returned objects will be empty.</param>
269+
/// <returns>An enumeration of the values returned from a data reader.</returns>
270+
public static IEnumerable<object[]> AsEnumerable(this IDataReader reader, IEnumerable<int> ordinals)
271+
=> AsEnumerableInternal(reader, ordinals, false);
272+
269273
/// <summary>
270274
/// Enumerates all the remaining values of the current result set of a data reader.
271275
/// </summary>
@@ -769,30 +773,18 @@ public static Dictionary<string, object> ToDictionary(this IDataRecord record, p
769773
public static Dictionary<string, object> ToDictionary(this IDataRecord record, IEnumerable<string> columnNames)
770774
=> ToDictionary(record, new HashSet<string>(columnNames));
771775

772-
static QueryResult<Queue<object[]>> RetrieveBlanksInternal(IDataReader reader)
773-
=> new QueryResult<Queue<object[]>>(
774-
Array.Empty<int>(),
775-
Array.Empty<string>(),
776-
new Queue<object[]>(AsEnumerable(reader, Enumerable.Empty<int>())));
777776

778-
static QueryResult<Queue<object[]>> RetrieveInternal(this IDataReader reader, int[] ordinals, string[] columnNames = null)
777+
778+
static QueryResult<Queue<object[]>> RetrieveInternal(this IDataReader reader, int[] ordinals, string[] columnNames = null, bool readStarted = false)
779779
{
780780
var fieldCount = ordinals.Length;
781781
if (columnNames == null) columnNames = ordinals.Select(n => reader.GetName(n)).ToArray();
782782
else if (columnNames.Length != fieldCount) throw new ArgumentException("Mismatched array lengths of ordinals and names.");
783783

784-
if (fieldCount == 0)
785-
{
786-
// No column names specified? Then return results, but empty ones. Simplify the results for counting.
787-
return RetrieveBlanksInternal(reader);
788-
}
789-
else
790-
{
791-
return new QueryResult<Queue<object[]>>(
792-
ordinals,
793-
columnNames,
794-
new Queue<object[]>(AsEnumerable(reader, ordinals)));
795-
}
784+
return new QueryResult<Queue<object[]>>(
785+
ordinals,
786+
columnNames,
787+
new Queue<object[]>(AsEnumerableInternal(reader, ordinals, readStarted)));
796788
}
797789

798790
/// <summary>
@@ -908,13 +900,15 @@ public static QueryResult<Queue<object[]>> Retrieve(this IDbCommand command, str
908900
public static IEnumerable<T> Results<T>(this IDataReader reader, IEnumerable<(string Field, string Column)> fieldMappingOverrides)
909901
where T : new()
910902
{
903+
if (!reader.Read()) return Enumerable.Empty<T>();
904+
911905
var x = new Transformer<T>(fieldMappingOverrides);
912906
// Ignore missing columns.
913907
var columns = reader.GetMatchingOrdinals(x.ColumnNames, true);
914908

915909
return x.AsDequeueingEnumerable(RetrieveInternal(reader,
916910
columns.Select(c => c.Ordinal).ToArray(),
917-
columns.Select(c => c.Name).ToArray()));
911+
columns.Select(c => c.Name).ToArray(), readStarted: true));
918912
}
919913

920914
/// <summary>

QueryResult.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -172,14 +172,24 @@ public static ISourceBlock<T> To<T>(this QueryResult<ISourceBlock<object[]>> sou
172172
/// <returns>An block that dequeues the results and returns a column mapped dictionary for each entry</returns>
173173
public static ISourceBlock<T> To<T>(this QueryResult<ISourceBlock<object[]>> source, IEnumerable<KeyValuePair<string, string>> fieldMappingOverrides)
174174
where T : new()
175-
=> source.To<T>(fieldMappingOverrides?.Select(kvp => (kvp.Key, kvp.Value)));
175+
=> To<T>(source, fieldMappingOverrides?.Select(kvp => (kvp.Key, kvp.Value)));
176176

177-
/// <summary>
178-
/// Returns an enumerable that dequeues the results and returns a column mapped dictionary for each entry.
179-
/// </summary>
180-
/// <param name="source">The query result. Typically produced by a .Retrieve method.</param>
181-
/// <returns>An enumerable that dequeues the results and returns a column mapped dictionary for each entry</returns>
182-
public static IEnumerable<Dictionary<string, object>> AsMappedDictionaries(this QueryResult<IEnumerable<object[]>> source)
177+
/// <summary>
178+
/// Returns a block that attempts to map the fields to type T.
179+
/// </summary>
180+
/// <param name="source">The query result. Typically produced by a .Retrieve method.</param>
181+
/// <param name="fieldMappingOverrides">An optional override map of field names to column names where the keys are the property names, and values are the column names.</param>
182+
/// <returns>An block that dequeues the results and returns a column mapped dictionary for each entry</returns>
183+
public static ISourceBlock<T> To<T>(this QueryResult<ISourceBlock<object[]>> source, params (string Field, string Column)[] fieldMappingOverrides)
184+
where T : new()
185+
=> To<T>(source, fieldMappingOverrides as IEnumerable<(string Field, string Column)>);
186+
187+
/// <summary>
188+
/// Returns an enumerable that dequeues the results and returns a column mapped dictionary for each entry.
189+
/// </summary>
190+
/// <param name="source">The query result. Typically produced by a .Retrieve method.</param>
191+
/// <returns>An enumerable that dequeues the results and returns a column mapped dictionary for each entry</returns>
192+
public static IEnumerable<Dictionary<string, object>> AsMappedDictionaries(this QueryResult<IEnumerable<object[]>> source)
183193
{
184194
var q = source.Result;
185195
var names = source.Names;

SqlClient/Extensions.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ public static async Task IterateReaderAsyncWhile(this SqlCommand command, Func<I
207207
public static async Task<QueryResult<Queue<object[]>>> RetrieveAsync(this SqlDataReader reader)
208208
{
209209
var fieldCount = reader.FieldCount;
210-
var names = reader.GetNames();
210+
var names = reader.GetNames(); // pull before first read.
211211
var buffer = new Queue<object[]>();
212212

213213
while (await reader.ReadAsync())
@@ -223,7 +223,7 @@ public static async Task<QueryResult<Queue<object[]>>> RetrieveAsync(this SqlDat
223223
buffer);
224224
}
225225

226-
static async Task<QueryResult<Queue<object[]>>> RetrieveAsyncInternal(SqlDataReader reader, int[] ordinals, string[] columnNames = null)
226+
static async Task<QueryResult<Queue<object[]>>> RetrieveAsyncInternal(SqlDataReader reader, int[] ordinals, string[] columnNames = null, bool readStarted = false)
227227
{
228228
var fieldCount = ordinals.Length;
229229
if (columnNames == null) columnNames = ordinals.Select(n => reader.GetName(n)).ToArray();
@@ -240,8 +240,14 @@ static async Task<QueryResult<Queue<object[]>>> RetrieveAsyncInternal(SqlDataRea
240240
};
241241

242242
var buffer = new Queue<object[]>();
243-
while (await reader.ReadAsync())
244-
buffer.Enqueue(handler(reader));
243+
if (readStarted || await reader.ReadAsync())
244+
{
245+
do
246+
{
247+
buffer.Enqueue(handler(reader));
248+
}
249+
while (await reader.ReadAsync());
250+
}
245251

246252
return new QueryResult<Queue<object[]>>(
247253
ordinals,
@@ -305,13 +311,15 @@ public static Task<QueryResult<Queue<object[]>>> RetrieveAsync(this SqlDataReade
305311
/// <returns>A task containing the list of results.</returns>
306312
public static async Task<IEnumerable<T>> ResultsAsync<T>(this SqlDataReader reader, IEnumerable<(string Field, string Column)> fieldMappingOverrides) where T : new()
307313
{
314+
if (!await reader.ReadAsync()) return Enumerable.Empty<T>();
315+
308316
var x = new Transformer<T>(fieldMappingOverrides);
309317
// Ignore missing columns.
310318
var columns = reader.GetMatchingOrdinals(x.ColumnNames, true);
311319

312320
return x.AsDequeueingEnumerable(await RetrieveAsyncInternal(reader,
313321
columns.Select(c => c.Ordinal).ToArray(),
314-
columns.Select(c => c.Name).ToArray()));
322+
columns.Select(c => c.Name).ToArray(), readStarted: true));
315323
}
316324

317325
/// <summary>

0 commit comments

Comments
 (0)