My favorites | Sign in
Project Home Source
Checkout   Browse   Changes    
 
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Squared.Task.Data.Mapper;
using Squared.Util.Bind;
using System.Linq.Expressions;
using System.Data;

namespace Squared.Task.Data {
public delegate IEnumerator<object> BoundMemberAdapterFunc (string name, IBoundMember member);

public class BoundMemberAdapter<T> {
public readonly Func<string, BoundMember<T>, IEnumerator<object>> Method;

public BoundMemberAdapter (
Func<string, BoundMember<T>, IEnumerator<object>> method
) {
Method = method;
}

public IEnumerator<object> Invoke (string name, IBoundMember member) {
return Method(name, (BoundMember<T>)member);
}
}

public struct BoundMemberAdapters {
public readonly BoundMemberAdapterFunc Load, Save;

public BoundMemberAdapters (BoundMemberAdapterFunc load, BoundMemberAdapterFunc save) {
Load = load;
Save = save;
}
}

public abstract class PropertySerializerBase : IDisposable {
protected readonly Dictionary<Type, BoundMemberAdapters> AdapterCache = new Dictionary<Type, BoundMemberAdapters>();

public readonly List<IBoundMember> Bindings = new List<IBoundMember>();

public Func<IBoundMember, string> GetMemberName;

public PropertySerializerBase (
Func<IBoundMember, string> getMemberName
) {
GetMemberName = getMemberName;
}

public void Bind<T> (Expression<Func<T>> target) {
Bindings.Add(BoundMember.New(target));
}

public static string GetDefaultMemberName (IBoundMember member) {
return member.Name;
}

public IEnumerator<object> Save () {
foreach (var member in Bindings) {
var name = GetMemberName(member);
var adapters = GetAdapters(member.Type);
yield return adapters.Save(name, member);
}
}

public IEnumerator<object> Load () {
foreach (var member in Bindings) {
var name = GetMemberName(member);
var adapters = GetAdapters(member.Type);
yield return adapters.Load(name, member);
}
}

protected BoundMemberAdapters GetAdapters (Type type) {
BoundMemberAdapters result;
if (AdapterCache.TryGetValue(type, out result))
return result;

var bmaFuncType = typeof(BoundMemberAdapterFunc);

var adapterType = typeof(BoundMemberAdapter<>)
.MakeGenericType(type);

Func<string, Delegate> getHelperMethod = (string name) => {
var method = GetType().GetMethod(
name, BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.FlattenHierarchy
).MakeGenericMethod(type);

var delegateType = typeof(Func<,,>)
.MakeGenericType(
typeof(string),
typeof(BoundMember<>)
.MakeGenericType(type),
typeof(IEnumerator<object>)
);

return Delegate.CreateDelegate(delegateType, this, method, true);
};

var loadAdapter = adapterType.GetConstructors()[0]
.Invoke(new object[] { getHelperMethod("LoadBinding") });

var saveAdapter = adapterType.GetConstructors()[0]
.Invoke(new object[] { getHelperMethod("SaveBinding") });

var invokeMethod = adapterType
.GetMethod("Invoke",
BindingFlags.Public | BindingFlags.Instance
);

result = new BoundMemberAdapters(
(BoundMemberAdapterFunc)Delegate.CreateDelegate(bmaFuncType, loadAdapter, invokeMethod, true),
(BoundMemberAdapterFunc)Delegate.CreateDelegate(bmaFuncType, saveAdapter, invokeMethod, true)
);
AdapterCache[type] = result;

return result;
}

protected abstract IEnumerator<object> LoadBinding<T> (string name, BoundMember<T> member);

protected abstract IEnumerator<object> SaveBinding<T> (string name, BoundMember<T> member);

public virtual void Dispose () {
Bindings.Clear();
}
}

public class DatabasePropertySerializer : PropertySerializerBase {
public readonly Query WriteValue;
public readonly Query ReadValue;

public DatabasePropertySerializer (
ConnectionWrapper database, string tableName
) : this (
database, tableName,
"name", "value"
) {
}

public DatabasePropertySerializer (
ConnectionWrapper database, string tableName,
string nameColumn, string valueColumn
) : this (
database, tableName,
nameColumn, valueColumn,
GetDefaultMemberName
) {
}

public DatabasePropertySerializer (
ConnectionWrapper database, string tableName,
string nameColumn, string valueColumn,
Func<IBoundMember, string> getMemberName
) : this (
database.BuildQuery(String.Format("REPLACE INTO {0} ({1}, {2}) VALUES (?, ?)", tableName, nameColumn, valueColumn)),
database.BuildQuery(String.Format("SELECT {2} FROM {0} WHERE {1} = ? LIMIT 1", tableName, nameColumn, valueColumn)),
getMemberName
) {
}

public DatabasePropertySerializer (
Query writeValue, Query readValue
) : this (
writeValue, readValue, GetDefaultMemberName
) {
}

public DatabasePropertySerializer (
Query writeValue, Query readValue,
Func<IBoundMember, string> getMemberName
) : base (getMemberName) {
WriteValue = writeValue;
writeValue.Parameters[0].DbType = DbType.String;
writeValue.Parameters[1].DbType = DbType.Object;
ReadValue = readValue;
readValue.Parameters[0].DbType = DbType.String;
}

protected override IEnumerator<object> SaveBinding<T> (string name, BoundMember<T> member) {
yield return WriteValue.ExecuteNonQuery(name, member.Value);
}

protected override IEnumerator<object> LoadBinding<T> (string name, BoundMember<T> member) {
var fReader = ReadValue.ExecuteReader(name);
yield return fReader;

using (var reader = fReader.Result) {
if (reader.Reader.Read())
member.Value = DataRecordHelper.GetReadMethod<T>()
(reader.Reader, 0);
}
}

override public void Dispose () {
WriteValue.Dispose();
ReadValue.Dispose();
}
}
}

Change log

r434 by kevin.gadd on Apr 8, 2011   Diff
PropertySerializer renamed to
DatabasePropertySerializer, with
bookkeeping logic pulled up into an
abstract base class to enable alternate
property serializer backends
Tests updated to build after
GetCompletionEvent changed
Go to: 
Project members, sign in to write a code review

Older revisions

r421 by kevin.gadd on Mar 18, 2011   Diff
More code cleanup
Removing the Future class since it
just inherits Future<object> and
introduces type trouble. Use
Future<object> now. Methods that used
...
r420 by kevin.gadd on Mar 18, 2011   Diff
Code cleanups and dead code removal
r361 by kevin.gadd on Mar 6, 2010   Diff
Data.Query exposes a Parameters
property now
Added the Data.PropertySerializer
helper class to encapsulate automatic
database serialization of
...
All revisions of this file

File info

Size: 7282 bytes, 202 lines
Powered by Google Project Hosting