-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathObjectReader.cs
More file actions
131 lines (100 loc) · 5.44 KB
/
Copy pathObjectReader.cs
File metadata and controls
131 lines (100 loc) · 5.44 KB
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
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq.Expressions;
using System.Reflection;
namespace DataBoss.Data
{
public static class ObjectReader
{
delegate IEnumerator<T> ItemReader<T>(IDataReader reader, ConverterCollection converters, bool leaveOpen);
static class ItemReaderCache<T>
{
static readonly ConcurrentDictionary<Type, ItemReader<T>> readers = new();
public static ItemReader<T> GetReader(Type readerType) => readers.GetOrAdd(readerType, x => MakeReaderOfT<T>(x));
}
public static ObjectReader<TReader> For<TReader>(Func<TReader> reader) where TReader : IDataReader => new(reader);
public static Func<TReader, T> GetConverter<TReader, T>(TReader reader) where TReader : IDataReader =>
GetConverter<TReader, T>(reader, null);
public static Func<TReader, T> GetConverter<TReader, T>(TReader reader, ConverterCollection customConversions) where TReader : IDataReader =>
ConverterFactory(customConversions).GetConverter<TReader, T>(reader).Compiled;
public static Expression<Func<TReader, T>> MakeConverter<TReader, T>(TReader reader) where TReader : IDataReader =>
MakeConverter<TReader, T>(reader, null);
public static Expression<Func<TReader, T>> MakeConverter<TReader, T>(TReader reader, ConverterCollection customConversions) where TReader : IDataReader =>
ConverterFactory(customConversions).GetConverter<TReader, T>(reader).Expression;
public static IEnumerator<T> Read<T>(this IDataReader reader) =>
Read<T>(reader, null);
public static IEnumerator<T> Read<T>(this IDataReader reader, bool leaveOpen) =>
Read<T>(reader, null, leaveOpen: leaveOpen);
public static IEnumerator<T> Read<T>(this IDataReader reader, ConverterCollection converters) =>
Read<T>(reader, converters, false);
public static IEnumerator<T> Read<T>(this IDataReader reader, ConverterCollection converters, bool leaveOpen) =>
ItemReaderCache<T>.GetReader(reader.GetType())(reader, converters, leaveOpen);
public static void Read<TReader, T>(this TReader reader, Action<T> handleItem) where TReader : IDataReader =>
Read(reader, handleItem, null);
public static void Read<TReader, T>(this TReader reader, Action<T> handleItem, ConverterCollection converters) where TReader : IDataReader {
using var items = new ConvertingEnumerator<TReader, T>(reader, GetConverter<TReader, T>(reader, converters));
while (items.MoveNext())
handleItem(items.Current);
}
public static IEnumerable<T> Enumerable<T>(Func<IDataReader> getData, ConverterCollection converters) {
using var items = Read<T>(getData(), converters);
while (items.MoveNext())
yield return items.Current;
}
static ItemReader<T> MakeReaderOfT<T>(Type readerType) {
var m = typeof(ObjectReader).GetMethod(nameof(ReaderOfT), BindingFlags.NonPublic | BindingFlags.Static);
return Lambdas.CreateDelegate<ItemReader<T>>(m.MakeGenericMethod(readerType, typeof(T)));
}
static IEnumerator<T> ReaderOfT<TReader, T>(IDataReader reader, ConverterCollection converters, bool leaveOpen) where TReader : IDataReader {
var readerOfT = (TReader)reader;
return new ConvertingEnumerator<TReader, T>(readerOfT, GetConverter<TReader, T>(readerOfT, converters), leaveOpen);
}
static ConverterFactory ConverterFactory(ConverterCollection customConversions) => new(customConversions, NullConverterCache.Instance);
}
public struct ObjectReader<TReader> where TReader : IDataReader
{
readonly Func<TReader> getReader;
public ObjectReader(Func<TReader> getReader) {
this.getReader = getReader;
}
public ConvertingObjectReader<TReader> WithConverter<TFrom, TTo>(Func<TFrom, TTo> convert) =>
new ConvertingObjectReader<TReader>(this).WithConverter(convert);
public IEnumerator<T> Read<T>() => Read<T>((ConverterCollection)null);
public IEnumerator<T> Read<T>(ConverterCollection converters) {
var reader = getReader();
return new ConvertingEnumerator<TReader, T>(reader, GetConverter<T>(reader, converters));
}
public IEnumerator<T> Read<T>(ConverterFactory converters) {
var reader = getReader();
return new ConvertingEnumerator<TReader, T>(reader, converters.GetConverter<TReader, T>(reader).Compiled);
}
public void Read<T>(Action<T> handleItem) => Read(null, handleItem);
public void Read<T>(ConverterCollection converters, Action<T> handleItem) {
using var reader = getReader();
Func<TReader, T> converter = GetConverter<T>(reader, converters);
while (reader.Read())
handleItem(converter(reader));
}
private static Func<TReader, T> GetConverter<T>(TReader reader, ConverterCollection converters) {
return ObjectReader.GetConverter<TReader, T>(reader, converters);
}
}
public sealed class ConvertingObjectReader<TReader> where TReader : IDataReader
{
readonly ObjectReader<TReader> reader;
readonly ConverterCollection customConversions;
public ConvertingObjectReader(ObjectReader<TReader> reader) {
this.reader = reader;
this.customConversions = new ConverterCollection();
}
public ConvertingObjectReader<TReader> WithConverter<TFrom, TTo>(Func<TFrom, TTo> convert) {
customConversions.Add(convert);
return this;
}
public IEnumerator<T> Read<T>() => reader.Read<T>(customConversions);
public void Read<T>(Action<T> handleItem) => reader.Read(customConversions, handleItem);
}
}