-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy path_.cs
230 lines (199 loc) · 8.73 KB
/
_.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
using System.Linq.Expressions;
namespace Open.Database.Extensions;
/// <summary>
/// Core non-DB-specific extensions for building a command and retrieving data using best practices.
/// </summary>
public static partial class CoreExtensions
{
internal static IEnumerable<T> Concat<T>(T first, ICollection<T> remaining)
=> (remaining == null || remaining.Count == 0) ? [first] : remaining.Prepend(first);
// https://stackoverflow.com/questions/17660097/is-it-possible-to-speed-this-method-up/17669142#17669142
internal static Action<T, object?> BuildUntypedSetter<T>(this PropertyInfo propertyInfo)
{
var targetType = propertyInfo.DeclaringType;
var exTarget = Expression.Parameter(targetType ?? throw new InvalidOperationException(), "t");
var exValue = Expression.Parameter(typeof(object), "p");
var methodInfo = propertyInfo.GetSetMethod();
var exBody = Expression.Call(exTarget, methodInfo!,
Expression.Convert(exValue, propertyInfo.PropertyType));
var lambda = Expression.Lambda<Action<T, object?>>(exBody, exTarget, exValue);
return lambda.Compile();
}
internal static object? DBNullValueToNull(object? value)
=> value == DBNull.Value ? null : value;
/// <summary>
/// Copies the contents of the <paramref name="values"/> span
/// to the <paramref name="target"/> span
/// with any <see cref="DBNull"/> values converted to <see langword="null"/>.
/// </summary>
public static Span<object?> CopyToDBNullAsNull(this ReadOnlySpan<object?> values, Span<object?> target)
{
int len = values.Length;
object?[] result = new object?[len];
for (int i = 0; i < len; i++)
target[i] = DBNullValueToNull(values[i]);
return result;
}
/// <inheritdoc cref="CopyToDBNullAsNull(ReadOnlySpan{object?}, Span{object?})"/>
public static Span<object?> CopyToDBNullAsNull(this Span<object?> values, Span<object?> target)
=> CopyToDBNullAsNull((ReadOnlySpan<object?>)values, target);
/// <inheritdoc cref="CopyToDBNullAsNull(ReadOnlySpan{object?}, Span{object?})"/>
public static Span<object?> CopyToDBNullAsNull(this ReadOnlySpan<object?> values, Memory<object?> target)
=> CopyToDBNullAsNull(values, target.Span);
/// <inheritdoc cref="CopyToDBNullAsNull(ReadOnlySpan{object?}, Span{object?})"/>
public static Span<object?> CopyToDBNullAsNull(this Span<object?> values, Memory<object?> target)
=> CopyToDBNullAsNull((ReadOnlySpan<object?>)values, target.Span);
/// <summary>
/// Any <see cref="DBNull"/> values are yielded as null.
/// </summary>
/// <param name="values">The source enumerable.</param>
public static IEnumerable<object?> DBNullToNull(this IEnumerable<object?> values)
{
return DBNullToNullCore(values ?? throw new ArgumentNullException(nameof(values)));
static IEnumerable<object?> DBNullToNullCore(IEnumerable<object?> values)
{
foreach (object? v in values)
yield return DBNullValueToNull(v);
}
}
/// <summary>
/// Returns a copy of <paramref name="values"/> with any <see cref="DBNull"/> values converted to null.
/// </summary>
/// <param name="values">The source values.</param>
public static object?[] DBNullToNullCopy(this object?[] values)
{
if (values is null) throw new ArgumentNullException(nameof(values));
Contract.EndContractBlock();
object?[] result = new object?[values.Length];
CopyToDBNullAsNull(values.AsSpan(), result.AsSpan());
return result;
}
/// <summary>
/// Returns a copy of the contents of this span as an array with any <see cref="DBNull"/> values converted to null.
/// </summary>
/// <inheritdoc cref="DBNullToNullCopy(object[])"/>
public static object?[] DBNullToNullCopy(this ReadOnlySpan<object?> values)
{
object?[] result = new object?[values.Length];
CopyToDBNullAsNull(values, result.AsSpan());
return result;
}
/// <inheritdoc cref="DBNullToNullCopy(ReadOnlySpan{object?})"/>
public static object?[] DBNullToNullCopy(this Span<object?> values)
=> DBNullToNullCopy((ReadOnlySpan<object?>)values);
/// <summary>
/// Replaces any <see cref="DBNull"/> in the <paramref name="values"/> with null;
/// </summary>
/// <param name="values">The source values.</param>
public static Span<object?> ReplaceDBNullWithNull(this Span<object?> values)
=> CopyToDBNullAsNull(values, values);
/// <inheritdoc cref="ReplaceDBNullWithNull(Span{object?})"/>
public static Memory<object?> ReplaceDBNullWithNull(this Memory<object?> values)
{
CopyToDBNullAsNull(values.Span, values.Span);
return values;
}
/// <inheritdoc cref="ReplaceDBNullWithNull(Span{object?})"/>
public static object?[] ReplaceDBNullWithNull(this object?[] values)
{
if (values is null) throw new ArgumentNullException(nameof(values));
Contract.EndContractBlock();
values.AsSpan().ReplaceDBNullWithNull();
return values;
}
/// <inheritdoc cref="ReplaceDBNullWithNull(Span{object?})"/>
public static List<object?> ReplaceDBNullWithNull(this List<object?> values)
{
if (values is null) throw new ArgumentNullException(nameof(values));
Contract.EndContractBlock();
#if NET8_0_OR_GREATER
var span = System.Runtime.InteropServices.CollectionsMarshal.AsSpan(values);
for (int i = 0; i < span.Length; i++)
{
ref object? item = ref span[i];
if (item == DBNull.Value) item = null;
}
#else
int count = values.Count;
for (int i = 0; i < count; i++)
{
if (values[i] == DBNull.Value) values[i] = null;
}
#endif
return values;
}
/// <summary>
/// Generic enumerable extension for <see cref="DataColumnCollection"/>.
/// </summary>
/// <param name="columns">The column collection.</param>
/// <returns>An enumerable of <see cref="DataColumn"/>s.</returns>
public static IEnumerable<DataColumn> AsEnumerable(this DataColumnCollection columns)
{
return columns is null
? throw new ArgumentNullException(nameof(columns))
: AsEnumerableCore(columns);
static IEnumerable<DataColumn> AsEnumerableCore(DataColumnCollection columns)
{
foreach (DataColumn c in columns)
yield return c;
}
}
/// <summary>
/// Generic enumerable extension for <see cref="DataRowCollection"/>.
/// </summary>
/// <param name="rows">The row collection.</param>
/// <returns>An enumerable of <see cref="DataRow"/>s.</returns>
public static IEnumerable<DataRow> AsEnumerable(this DataRowCollection rows)
{
return rows is null
? throw new ArgumentNullException(nameof(rows))
: AsEnumerableCore(rows);
static IEnumerable<DataRow> AsEnumerableCore(DataRowCollection rows)
{
foreach (DataRow r in rows)
yield return r;
}
}
/// <inheritdoc cref="To{T}(DataTable, IEnumerable{KeyValuePair{string, string?}}?, bool)"/>
public static IEnumerable<T> To<T>(this DataTable table, IEnumerable<(string Field, string? Column)>? fieldMappingOverrides, bool clearSourceTable = false) where T : new()
=> Transformer<T>
.Create(fieldMappingOverrides)
.Results(table, clearSourceTable);
/// <inheritdoc cref="To{T}(DataTable, IEnumerable{KeyValuePair{string, string?}}?, bool)"/>
#if NET8_0_OR_GREATER
public static IEnumerable<T> To<T>(this DataTable table, params IEnumerable<(string Field, string? Column)> fieldMappingOverrides) where T : new()
#else
public static IEnumerable<T> To<T>(this DataTable table, params (string Field, string? Column)[] fieldMappingOverrides) where T : new()
#endif
=> Transformer<T>
.Create(fieldMappingOverrides)
.Results(table, false);
/// <summary>
/// Loads all data into a queue before iterating (dequeuing) the results as type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The model type to map the values to (using reflection).</typeparam>
/// <param name="table">The <see cref="DataTable"/> to read from.</param>
/// <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>
/// <param name="clearSourceTable">Clears the source table before providing the enumeration.</param>
/// <returns>An enumerable used to iterate the results.</returns>
public static IEnumerable<T> To<T>(this DataTable table, IEnumerable<KeyValuePair<string, string?>>? fieldMappingOverrides, bool clearSourceTable = false) where T : new()
=> To<T>(table, fieldMappingOverrides?.Select(kvp => (kvp.Key, kvp.Value)), clearSourceTable);
/// <summary>
/// Useful extension for dequeuing items from a queue.
/// Not thread safe but queueing/dequeuing items in between items is supported.
/// </summary>
/// <typeparam name="T">Return type of the source queue</typeparam>
/// <returns>An enumerable of the items contained within the queue.</returns>
public static IEnumerable<T> DequeueEach<T>(this Queue<T> source)
{
if (source is null) throw new ArgumentNullException(nameof(source));
Contract.EndContractBlock();
#if NETSTANDARD2_0
while (source.Count != 0)
yield return source.Dequeue();
#else
while (source.TryDequeue(out T? a))
yield return a;
#endif
}
}