Skip to content

Commit c20b29b

Browse files
Refactor DbConnection classes and improve documentation
- Renamed `TakenConnectionState` to `_takenConnectionState` in `DbConnectionProvider<TConnection>` for clarity. - Updated `QueryResult<TResult>` constructor to initialize `Ordinals` and `Names` properties. - Reformatted `DbConnectionFactory<TConnection>` for better readability. - Enhanced documentation in `IExecuteReaderExtensions` for improved clarity. - Added methods in `CoreExtensions` for efficient handling of `DBNull` values. - Refactored `DBNullToNullCopy` to utilize new methods for better efficiency. - Replaced `PoolFromFactory` with `ConnectionFactoryToPoolAdapter` struct in `IDbConnectionFactory<TConnection>`. - Updated `AsPool` methods to return the new adapter struct for consistency. - Improved null checking in `AsGeneric` method of `IDbConnectionFactory`.
1 parent 11bf56d commit c20b29b

File tree

6 files changed

+74
-52
lines changed

6 files changed

+74
-52
lines changed

Source/Core/Core/DbConnectionProvider.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ internal class DbConnectionProvider<TConnection>(TConnection connection)
99
{
1010
private TConnection Connection { get; } = connection ?? throw new ArgumentNullException(nameof(connection));
1111

12-
private ConnectionState? TakenConnectionState;
12+
private ConnectionState? _takenConnectionState;
1313

1414
/// <inheritdoc />
1515
public TConnection Take()
1616
{
17-
if (TakenConnectionState.HasValue)
17+
if (_takenConnectionState.HasValue)
1818
throw new InvalidOperationException("Concurrent use of a single connection is not supported.");
1919

20-
TakenConnectionState = Connection.State;
20+
_takenConnectionState = Connection.State;
2121
return Connection;
2222
}
2323

@@ -32,10 +32,10 @@ public void Give(IDbConnection connection)
3232
throw new ArgumentException("Does not belong to this provider.", nameof(connection));
3333
Contract.EndContractBlock();
3434

35-
if (TakenConnectionState == ConnectionState.Closed)
35+
if (_takenConnectionState == ConnectionState.Closed)
3636
connection.Close();
3737

38-
TakenConnectionState = null;
38+
_takenConnectionState = null;
3939
}
4040
}
4141

Source/Core/Core/QueryResult.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public QueryResult(
1919
{
2020
if (ordinals.Length != names.Length)
2121
throw new ArgumentException("Mismatched array lengths of ordinals and names.");
22+
2223
Ordinals = ordinals;
2324
Names = names;
2425
Result = result;

Source/Core/DbConnectionFactory.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ public static implicit operator DbConnectionFactory(Func<IDbConnection> factory)
4343
/// Generic connection factory implementation that accepts a factory function.
4444
/// </summary>
4545
/// <typeparam name="TConnection">The connection type.</typeparam>
46-
public class DbConnectionFactory<TConnection> : DbConnectionFactory, IDbConnectionFactory<TConnection>
46+
public class DbConnectionFactory<TConnection>
47+
: DbConnectionFactory, IDbConnectionFactory<TConnection>
4748
where TConnection : IDbConnection
4849
{
4950
readonly Func<TConnection> _factory;

Source/Core/Extensions/IExecuteReader.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ public static T First<T>(this IExecuteReader command, Func<IDataRecord, T> trans
165165
}
166166

167167
/// <summary>
168-
/// Iterates a IDataReader and returns the first result through a transform function. Throws if none or more than one entry.
168+
/// Iterates a IDataReader and returns the first result through a transform function.
169+
/// Throws if none or more than one entry.
169170
/// </summary>
170171
/// <typeparam name="T">The return type of the transform function.</typeparam>
171172
/// <param name="command">The IExecuteReader to iterate.</param>
@@ -183,7 +184,9 @@ public static T Single<T>(this IExecuteReader command, Func<IDataRecord, T> tran
183184
}
184185

185186
/// <summary>
186-
/// Iterates an IDataReader and returns the first result through a transform function. Returns default(T) if none. Throws if more than one entry.
187+
/// Iterates an IDataReader and returns the first result through a transform function.
188+
/// Returns default(T) if none.
189+
/// Throws if more than one entry.
187190
/// </summary>
188191
/// <typeparam name="T">The return type of the transform function.</typeparam>
189192
/// <param name="command">The IExecuteReader to iterate.</param>

Source/Core/Extensions/_.cs

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,32 @@ internal static IEnumerable<T> Concat<T>(T first, ICollection<T> remaining)
2626
internal static object? DBNullValueToNull(object? value)
2727
=> value == DBNull.Value ? null : value;
2828

29+
/// <summary>
30+
/// Copies the contents of the <paramref name="values"/> span
31+
/// to the <paramref name="target"/> span
32+
/// with any <see cref="DBNull"/> values converted to <see langword="null"/>.
33+
/// </summary>
34+
public static Span<object?> CopyToWithDbNullAsNull(this ReadOnlySpan<object?> values, Span<object?> target)
35+
{
36+
int len = values.Length;
37+
object?[] result = new object?[len];
38+
for (int i = 0; i < len; i++)
39+
target[i] = DBNullValueToNull(values[i]);
40+
41+
return result;
42+
}
43+
44+
/// <inheritdoc cref="CopyToWithDbNullAsNull(ReadOnlySpan{object?}, Span{object?})"/>
45+
public static Span<object?> CopyToWithDbNullAsNull(this Span<object?> values, Span<object?> target)
46+
=> CopyToWithDbNullAsNull((ReadOnlySpan<object?>)values, target);
47+
2948
/// <summary>
3049
/// Any <see cref="DBNull"/> values are yielded as null.
3150
/// </summary>
3251
/// <param name="values">The source enumerable.</param>
3352
public static IEnumerable<object?> DBNullToNull(this IEnumerable<object?> values)
3453
{
35-
return values is null
36-
? throw new ArgumentNullException(nameof(values))
37-
: DBNullToNullCore(values);
54+
return DBNullToNullCore(values ?? throw new ArgumentNullException(nameof(values)));
3855

3956
static IEnumerable<object?> DBNullToNullCore(IEnumerable<object?> values)
4057
{
@@ -52,10 +69,8 @@ internal static IEnumerable<T> Concat<T>(T first, ICollection<T> remaining)
5269
if (values is null) throw new ArgumentNullException(nameof(values));
5370
Contract.EndContractBlock();
5471

55-
int len = values.Length;
56-
object?[] result = new object?[len];
57-
for (int i = 0; i < len; i++)
58-
result[i] = DBNullValueToNull(values[i]);
72+
object?[] result = new object?[values.Length];
73+
CopyToWithDbNullAsNull(values.AsSpan(), result.AsSpan());
5974
return result;
6075
}
6176

@@ -65,38 +80,21 @@ internal static IEnumerable<T> Concat<T>(T first, ICollection<T> remaining)
6580
/// <inheritdoc cref="DBNullToNullCopy(object[])"/>
6681
public static object?[] DBNullToNullCopy(this ReadOnlySpan<object?> values)
6782
{
68-
int len = values.Length;
69-
object?[] result = new object?[len];
70-
for (int i = 0; i < len; i++)
71-
result[i] = DBNullValueToNull(values[i]);
83+
object?[] result = new object?[values.Length];
84+
DBNullToNullCopy(values, result.AsSpan());
7285
return result;
7386
}
7487

7588
/// <inheritdoc cref="DBNullToNullCopy(ReadOnlySpan{object?})"/>
7689
public static object?[] DBNullToNullCopy(this Span<object?> values)
77-
{
78-
int len = values.Length;
79-
object?[] result = new object?[len];
80-
for (int i = 0; i < len; i++)
81-
result[i] = DBNullValueToNull(values[i]);
82-
return result;
83-
}
90+
=> DBNullToNullCopy((ReadOnlySpan<object?>)values);
8491

8592
/// <summary>
8693
/// Replaces any <see cref="DBNull"/> in the <paramref name="values"/> with null;
8794
/// </summary>
8895
/// <param name="values">The source values.</param>
8996
public static Span<object?> ReplaceDBNullWithNull(this Span<object?> values)
90-
{
91-
int len = values.Length;
92-
for (int i = 0; i < len; i++)
93-
{
94-
ref object? value = ref values[i];
95-
if (value == DBNull.Value) value = null;
96-
}
97-
98-
return values;
99-
}
97+
=> DBNullToNullCopy(values, values);
10098

10199
/// <inheritdoc cref="ReplaceDBNullWithNull(Span{object?})"/>
102100
public static object?[] ReplaceDBNullWithNull(this object?[] values)

Source/Core/IDbConnectionFactory.cs

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,44 @@ public interface IDbConnectionFactory<out TConnection> : IDbConnectionFactory
2727
/// </summary>
2828
public static class DbConnectionFactoryExtensions
2929
{
30-
class PoolFromFactory(IDbConnectionFactory connectionFactory) : IDbConnectionPool
30+
/// <summary>
31+
/// A struct that represents a connection factory that can be used as a pool.
32+
/// </summary>
33+
public readonly struct ConnectionFactoryToPoolAdapter(Func<IDbConnection> factory) : IDbConnectionPool
3134
{
32-
private readonly IDbConnectionFactory _connectionFactory
33-
= connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
35+
/// <summary>
36+
/// Constructs a connection factory to pool adapter.
37+
/// </summary>
38+
public ConnectionFactoryToPoolAdapter(IDbConnectionFactory factory)
39+
: this(factory.Create) { }
3440

41+
/// <inheritdoc />
3542
public IDbConnection Take()
36-
=> _connectionFactory.Create();
43+
=> factory();
3744

45+
/// <inheritdoc />
3846
public void Give(IDbConnection connection)
3947
=> connection.Dispose();
4048
}
4149

42-
class PoolFromFactory<TConnection>(IDbConnectionFactory<TConnection> connectionFactory) : IDbConnectionPool<TConnection>
50+
/// <inheritdoc cref="ConnectionFactoryToPoolAdapter(Func{IDbConnection})" />/>
51+
public readonly struct ConnectionFactoryToPoolAdapter<TConnection>(Func<TConnection> factory) : IDbConnectionPool<TConnection>
4352
where TConnection : IDbConnection
4453
{
45-
private readonly IDbConnectionFactory<TConnection> _connectionFactory
46-
= connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
54+
/// <summary>
55+
/// Constructs a connection factory to pool adapter.
56+
/// </summary>
57+
public ConnectionFactoryToPoolAdapter(IDbConnectionFactory<TConnection> factory)
58+
: this(factory.Create) { }
4759

60+
/// <inheritdoc />
4861
public TConnection Take()
49-
=> _connectionFactory.Create();
62+
=> factory();
5063

5164
IDbConnection IDbConnectionPool.Take()
5265
=> Take();
5366

67+
/// <inheritdoc />
5468
public void Give(IDbConnection connection)
5569
=> connection.Dispose();
5670
}
@@ -59,25 +73,30 @@ public void Give(IDbConnection connection)
5973
/// Provides a connection pool that simply creates from a connection factory and disposes when returned.
6074
/// </summary>
6175
/// <param name="connectionFactory">The connection factory to generate connections from.</param>
62-
/// <returns></returns>
63-
public static IDbConnectionPool AsPool(this IDbConnectionFactory connectionFactory)
64-
=> new PoolFromFactory(connectionFactory);
76+
/// <returns>An <see cref="ConnectionFactoryToPoolAdapter"/> to handle this factory.</returns>
77+
public static ConnectionFactoryToPoolAdapter AsPool(this IDbConnectionFactory connectionFactory)
78+
=> new (connectionFactory);
6579

6680
/// <summary>
6781
/// Provides a connection pool that simply creates from a connection factory and disposes when returned.
6882
/// </summary>
6983
/// <param name="connectionFactory">The connection factory to generate connections from.</param>
70-
/// <returns></returns>
71-
public static IDbConnectionPool<TConnection> AsPool<TConnection>(this IDbConnectionFactory<TConnection> connectionFactory)
84+
/// <returns>An <see cref="ConnectionFactoryToPoolAdapter{TConnection}"/> to handle this factory.</returns>
85+
public static ConnectionFactoryToPoolAdapter<TConnection> AsPool<TConnection>(this IDbConnectionFactory<TConnection> connectionFactory)
7286
where TConnection : IDbConnection
73-
=> new PoolFromFactory<TConnection>(connectionFactory);
87+
=> new (connectionFactory);
7488

7589
/// <summary>
7690
/// Coerces a non-generic connection factory to a generic one.
7791
/// </summary>
7892
/// <param name="connectionFactory">The source connection factory.</param>
7993
/// <returns>The generic version of the source factory.</returns>
8094
public static IDbConnectionFactory<IDbConnection> AsGeneric(this IDbConnectionFactory connectionFactory)
81-
=> (connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory))) is IDbConnectionFactory<IDbConnection> p ? p
82-
: new DbConnectionFactory<IDbConnection>(() => connectionFactory.Create());
95+
{
96+
if (connectionFactory is null) throw new ArgumentNullException(nameof(connectionFactory));
97+
Contract.EndContractBlock();
98+
99+
return connectionFactory is IDbConnectionFactory<IDbConnection> p ? p
100+
: new DbConnectionFactory<IDbConnection>(connectionFactory.Create);
101+
}
83102
}

0 commit comments

Comments
 (0)