Skip to content

Commit

Permalink
datareaer mapping extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
pimbrouwers committed Jun 19, 2024
1 parent 329dd21 commit 3b0a467
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 151 deletions.
254 changes: 120 additions & 134 deletions src/Spiffy/Extensions/DbCommandExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,157 +7,143 @@

namespace Spiffy
{
/// <summary>
/// DbCommand extension methods for async workloads
/// </summary>
public static class DbCommandExtensions
{
/// <summary>
/// Asynchronously execute parameterized query with no results
/// DbCommand extension methods for async workloads
/// </summary>
/// <param name="dbCommand"></param>
/// <returns></returns>
public async static Task ExecAsync(this DbCommand dbCommand) =>
await dbCommand.DoVoidAsync(async cmd => await cmd.ExecuteNonQueryAsync());
public static class DbCommandExtensions
{
/// <summary>
/// Asynchronously execute parameterized query with no results
/// </summary>
/// <param name="dbCommand"></param>
/// <returns></returns>
public async static Task ExecAsync(this DbCommand dbCommand) =>
await dbCommand.DoVoidAsync(async cmd => await cmd.ExecuteNonQueryAsync());

/// <summary>
/// Asynchronously execute parameterized query many times with no results
/// </summary>
/// <param name="dbCommand"></param>
/// <param name="paramList"></param>
/// <returns></returns>
public async static Task ExecManyAsync(this DbCommand dbCommand, IEnumerable<DbParams> paramList) =>
await dbCommand.DoManyAsync(paramList, async cmd => await cmd.ExecuteNonQueryAsync());
/// <summary>
/// Asynchronously execute parameterized query many times with no results
/// </summary>
/// <param name="dbCommand"></param>
/// <param name="paramList"></param>
/// <returns></returns>
public async static Task ExecManyAsync(this DbCommand dbCommand, IEnumerable<DbParams> paramList) =>
await dbCommand.DoManyAsync(paramList, async cmd => await cmd.ExecuteNonQueryAsync());

/// <summary>
/// Asynchronously execute parameterized query and return single object value.
/// </summary>
/// <param name="dbCommand"></param>
/// <returns></returns>
public static async Task<object> ScalarAsync(this DbCommand dbCommand) =>
await dbCommand.DoAsync(async cmd => await cmd.ExecuteScalarAsync());
/// <summary>
/// Asynchronously execute parameterized query and return single object value.
/// </summary>
/// <param name="dbCommand"></param>
/// <returns></returns>
public static async Task<object> ScalarAsync(this DbCommand dbCommand) =>
await dbCommand.DoAsync(async cmd => await cmd.ExecuteScalarAsync());

/// <summary>
/// Asynchronously execute parameterized query, enumerate all records and apply mapping.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dbCommand"></param>
/// <param name="map"></param>
/// <param name="commandBehavior"></param>
/// <returns></returns>
public async static Task<IEnumerable<T>> QueryAsync<T>(this DbCommand dbCommand, Func<IDataReader, T> map, CommandBehavior commandBehavior = CommandBehavior.SequentialAccess) =>
await dbCommand.DoAsync(async cmd =>
{
using (var rd = await dbCommand.TryExecuteReaderAsync(commandBehavior))
{
var records = new List<T>();
/// <summary>
/// Asynchronously execute parameterized query, enumerate all records and apply mapping.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dbCommand"></param>
/// <param name="map"></param>
/// <param name="commandBehavior"></param>
/// <returns></returns>
public async static Task<IEnumerable<T>> QueryAsync<T>(this DbCommand dbCommand, Func<IDataReader, T> map, CommandBehavior commandBehavior = CommandBehavior.SequentialAccess) =>
await dbCommand.DoAsync(async cmd =>
{
using (var rd = await dbCommand.ExecuteReaderAsync(commandBehavior))
{
return await rd.MapAsync(map);
}
});

while (rd.Read())
/// <summary>
/// Asynchronously execute paramterized query, read only first record and apply mapping.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dbCommand"></param>
/// <param name="map"></param>
/// <param name="commandBehavior"></param>
/// <returns></returns>
public async static Task<T> QuerySingleAsync<T>(this DbCommand dbCommand, Func<IDataReader, T> map, CommandBehavior commandBehavior = CommandBehavior.SequentialAccess) =>
await dbCommand.DoAsync(async cmd =>
{
records.Add(map(rd));
}
using (var rd = await dbCommand.TryExecuteReaderAsync(commandBehavior))
{
return await rd.MapFirstAsync(map);
}
});

return records;
}
});
/// <summary>
/// Asynchronously execute paramterized query and manually cursor IDataReader.
/// <param name="dbCommand"></param>
/// <param name="read"></param>
/// <param name="commandBehavior"></param>
/// </summary>
public async static Task<T> ReadAsync<T>(this DbCommand dbCommand, Func<IDataReader, T> read, CommandBehavior commandBehavior = CommandBehavior.SequentialAccess) =>
await dbCommand.DoAsync(async cmd =>
{
using (var rd = await dbCommand.TryExecuteReaderAsync(commandBehavior))
{
return read(rd);
}
});

/// <summary>
/// Asynchronously execute paramterized query, read only first record and apply mapping.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dbCommand"></param>
/// <param name="map"></param>
/// <param name="commandBehavior"></param>
/// <returns></returns>
public async static Task<T> QuerySingleAsync<T>(this DbCommand dbCommand, Func<IDataReader, T> map, CommandBehavior commandBehavior = CommandBehavior.SequentialAccess) =>
await dbCommand.DoAsync(async cmd =>
{
using (var rd = await dbCommand.TryExecuteReaderAsync(commandBehavior))
private static async Task<T> DoAsync<T>(this DbCommand cmd, Func<DbCommand, Task<T>> func)
{
if (rd.Read())
{
return map(rd);
}
else
{
return default;
}
try
{
cmd.Connection.TryOpenConnection();
return await func(cmd);
}
catch (Exception ex)
{
cmd.TryRollback();
throw new FailedExecutionException(DbErrorCode.CouldNotExecuteNonQuery, cmd.CommandText, ex);
}
}
});

/// <summary>
/// Asynchronously execute paramterized query and manually cursor IDataReader.
/// <param name="dbCommand"></param>
/// <param name="read"></param>
/// <param name="commandBehavior"></param>
/// </summary>
public async static Task<T> ReadAsync<T>(this DbCommand dbCommand, Func<IDataReader, T> read, CommandBehavior commandBehavior = CommandBehavior.SequentialAccess) =>
await dbCommand.DoAsync(async cmd =>
{
using (var rd = await dbCommand.TryExecuteReaderAsync(commandBehavior))
private static async Task DoVoidAsync(this DbCommand cmd, Func<DbCommand, Task> func)
{
return read(rd);
try
{
cmd.Connection.TryOpenConnection();
await func(cmd);
}
catch (DbException ex)
{
cmd.TryRollback();
throw new FailedExecutionException(DbErrorCode.CouldNotExecuteNonQuery, cmd.CommandText, ex);
}
}
});

private static async Task<T> DoAsync<T>(this DbCommand cmd, Func<DbCommand, Task<T>> func)
{
try
{
cmd.Connection.TryOpenConnection();
return await func(cmd);
}
catch (Exception ex)
{
cmd.TryRollback();
throw new FailedExecutionException(DbErrorCode.CouldNotExecuteNonQuery, cmd.CommandText, ex);
}
}

private static async Task DoVoidAsync(this DbCommand cmd, Func<DbCommand, Task> func)
{
try
{
cmd.Connection.TryOpenConnection();
await func(cmd);
}
catch (DbException ex)
{
cmd.TryRollback();
throw new FailedExecutionException(DbErrorCode.CouldNotExecuteNonQuery, cmd.CommandText, ex);
}
}

private static async Task DoManyAsync(this DbCommand cmd, IEnumerable<DbParams> paramList, Func<DbCommand, Task> func)
{
try
{
cmd.Connection.TryOpenConnection();
foreach (var param in paramList)
private static async Task DoManyAsync(this DbCommand cmd, IEnumerable<DbParams> paramList, Func<DbCommand, Task> func)
{
cmd.Parameters.Clear();
cmd.SetDbParams(param);
await cmd.DoVoidAsync(func);
try
{
cmd.Connection.TryOpenConnection();
foreach (var param in paramList)
{
cmd.Parameters.Clear();
cmd.SetDbParams(param);
await cmd.DoVoidAsync(func);
}
}
catch (FailedExecutionException)
{
cmd.TryRollback();
throw;
}
}
}
catch (FailedExecutionException)
{
cmd.TryRollback();
throw;
}
}

private async static Task<IDataReader> TryExecuteReaderAsync(this DbCommand cmd, CommandBehavior commandBehavior)
{
try
{
cmd.Connection.TryOpenConnection();
return await cmd.ExecuteReaderAsync(commandBehavior);
}
catch (Exception ex)
{
throw new FailedExecutionException(DbErrorCode.CouldNotExecuteReader, cmd.CommandText, ex);
}
private async static Task<DbDataReader> TryExecuteReaderAsync(this DbCommand cmd, CommandBehavior commandBehavior)
{
try
{
cmd.Connection.TryOpenConnection();
return await cmd.ExecuteReaderAsync(commandBehavior);
}
catch (Exception ex)
{
throw new FailedExecutionException(DbErrorCode.CouldNotExecuteReader, cmd.CommandText, ex);
}
}
}
}
}
72 changes: 72 additions & 0 deletions src/Spiffy/Extensions/DbDataReaderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;

namespace Spiffy
{
/// <summary>
/// DbDataReader extension methods
/// </summary>
public static class DbDataReaderExtensions
{
/// <summary>
/// Asynchronously map DbDataReader to IEnumerable of T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="rd"></param>
/// <param name="map"></param>
/// <returns></returns>
public static async Task<IEnumerable<T>> MapAsync<T>(this DbDataReader rd, Func<DbDataReader, T> map)
{
var records = new List<T>();

while (await rd.ReadAsync())
{
records.Add(map(rd));
}

return records;
}

/// <summary>
/// Asynchronously map first iteration of DbDataReader to T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="rd"></param>
/// <param name="map"></param>
/// <returns></returns>
public static async Task<T> MapFirstAsync<T>(this DbDataReader rd, Func<DbDataReader, T> map)
{
if (await rd.ReadAsync())
{
return map(rd);
}
else
{
return default;
}
}

/// <summary>
/// Asynchronously map next iteration of DbDataReader to IEnumerable of T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="rd"></param>
/// <param name="map"></param>
/// <returns></returns>
public static async Task<IEnumerable<T>> MapNextAsync<T>(this DbDataReader rd, Func<DbDataReader, T> map) =>
await (rd.NextResult() ? rd.MapAsync(map) : Task.FromResult(Enumerable.Empty<T>()));

/// <summary>
/// Asynchronously map next iteration of DbDataReader to T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="rd"></param>
/// <param name="map"></param>
/// <returns></returns>
public static async Task<T> MapFirstNextAsync<T>(this DbDataReader rd, Func<DbDataReader, T> map) =>
await (rd.NextResult() ? rd.MapFirstAsync(map) : Task.FromResult<T>(default));
}
}
Loading

0 comments on commit 3b0a467

Please sign in to comment.