Skip to content

Commit 1eb5245

Browse files
committed
Merged changes from mongo test branch
1 parent 938ef5e commit 1eb5245

14 files changed

Lines changed: 482 additions & 43 deletions

CommonAssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@
1919
// COM, set the ComVisible attribute to true on that type.
2020
[assembly: ComVisible(false)]
2121

22-
[assembly: AssemblyVersion("0.4.6.1")]
23-
[assembly: AssemblyFileVersion("0.4.6.1")]
22+
[assembly: AssemblyVersion("0.5.0.0")]
23+
[assembly: AssemblyFileVersion("0.5.0.0")]

Simple.Data.Ado/ExpressionFormatter.cs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ public ExpressionFormatter(ICommandBuilder commandBuilder, DatabaseSchema schema
2323
{SimpleExpressionType.Or, LogicalExpressionToWhereClause},
2424
{SimpleExpressionType.Equal, EqualExpressionToWhereClause},
2525
{SimpleExpressionType.NotEqual, NotEqualExpressionToWhereClause},
26-
{SimpleExpressionType.Like, LikeExpressionToWhereClause},
27-
{SimpleExpressionType.NotLike, NotLikeExpressionToWhereClause},
26+
{SimpleExpressionType.Function, FunctionExpressionToWhereClause},
2827
{SimpleExpressionType.GreaterThan, expr => BinaryExpressionToWhereClause(expr, ">")},
2928
{SimpleExpressionType.GreaterThanOrEqual, expr => BinaryExpressionToWhereClause(expr, ">=")},
3029
{SimpleExpressionType.LessThan, expr => BinaryExpressionToWhereClause(expr, "<")},
@@ -80,18 +79,24 @@ private string NotEqualExpressionToWhereClause(SimpleExpression expression)
8079
FormatObject(expression.RightOperand));
8180
}
8281

83-
private string LikeExpressionToWhereClause(SimpleExpression expression)
82+
private string FunctionExpressionToWhereClause(SimpleExpression expression)
8483
{
85-
if (!(expression.RightOperand is string)) throw new InvalidOperationException("Cannot use Like on non-string type.");
86-
return string.Format("{0} LIKE {1}", FormatObject(expression.LeftOperand),
87-
FormatObject(expression.RightOperand));
88-
}
84+
var function = expression.RightOperand as SimpleFunction;
85+
if (function == null) throw new InvalidOperationException("Expected SimpleFunction as the right operand.");
8986

90-
private string NotLikeExpressionToWhereClause(SimpleExpression expression)
91-
{
92-
if (!(expression.RightOperand is string)) throw new InvalidOperationException("Cannot use Not Like on non-string type.");
93-
return string.Format("{0} NOT LIKE {1}", FormatObject(expression.LeftOperand),
94-
FormatObject(expression.RightOperand));
87+
if (function.Name.Equals("like", StringComparison.InvariantCultureIgnoreCase))
88+
{
89+
return string.Format("{0} LIKE {1}", FormatObject(expression.LeftOperand),
90+
FormatObject(function.Args[0]));
91+
}
92+
93+
if (function.Name.Equals("notlike", StringComparison.InvariantCultureIgnoreCase))
94+
{
95+
return string.Format("{0} NOT LIKE {1}", FormatObject(expression.LeftOperand),
96+
FormatObject(function.Args[0]));
97+
}
98+
99+
throw new NotSupportedException(string.Format("Unknown function '{0}'.", function.Name));
95100
}
96101

97102
private string BinaryExpressionToWhereClause(SimpleExpression expression, string comparisonOperator)

Simple.Data.SqlTest/app.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
</configSections>
55
<connectionStrings>
66
<add name="Simple.Data.SqlTest.Properties.Settings.ConnectionString"
7-
connectionString="Data Source=.;Initial Catalog=SimpleTest;Integrated Security=True"
7+
connectionString="Data Source=.\SQLSERVER2008;Initial Catalog=SimpleTest;Integrated Security=True"
88
providerName="System.Data.SqlClient" />
99
</connectionStrings>
1010
</configuration>

Simple.Data.UnitTest/DynamicEnumerableTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public void TestOfType()
2929
[Test]
3030
public void TestCastWithClass()
3131
{
32-
var dict = new Dictionary<string, object> {{"Name", "Bob"}};
32+
var dict = new Dictionary<string, object>(HomogenizedEqualityComparer.DefaultInstance) {{"Name", "Bob"}};
3333
dynamic test = new SimpleResultSet(new[] {new SimpleRecord(dict)});
3434
IEnumerable<Foo> foos = test.Cast<Foo>();
3535
Assert.AreEqual(1, foos.Count());
@@ -38,7 +38,7 @@ public void TestCastWithClass()
3838
[Test]
3939
public void TestCastWithForeach()
4040
{
41-
var dict = new Dictionary<string, object> { { "Name", "Bob" } };
41+
var dict = new Dictionary<string, object>(HomogenizedEqualityComparer.DefaultInstance) { { "Name", "Bob" } };
4242
dynamic test = new SimpleResultSet(new[] { new SimpleRecord(dict) });
4343
foreach (Foo foo in test)
4444
{

Simple.Data/Commands/UpdateCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ private static IDictionary<string,object> ObjectToDictionary(object obj)
5757
var dynamicRecord = obj as SimpleRecord;
5858
if (dynamicRecord != null)
5959
{
60-
return new Dictionary<string, object>(dynamicRecord);
60+
return new Dictionary<string, object>(dynamicRecord, HomogenizedEqualityComparer.DefaultInstance);
6161
}
6262

6363
return RegularObjectToDictionary(obj);
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Collections;
6+
using System.Dynamic;
7+
using System.Linq.Expressions;
8+
9+
namespace Simple.Data
10+
{
11+
internal static class ConcreteCollectionTypeCreator
12+
{
13+
private static readonly List<Creator> _creators = new List<Creator>
14+
{
15+
new GenericSetCreator(),
16+
new GenericListCreator(),
17+
new NonGenericListCreator()
18+
};
19+
20+
public static bool IsCollectionType(Type type)
21+
{
22+
return _creators.Any(c => c.IsCollectionType(type));
23+
}
24+
25+
public static bool TryCreate(Type type, IEnumerable items, out object result)
26+
{
27+
return _creators.First(c => c.IsCollectionType(type)).TryCreate(type, items, out result);
28+
}
29+
30+
private abstract class Creator
31+
{
32+
public abstract bool IsCollectionType(Type type);
33+
34+
public abstract bool TryCreate(Type type, IEnumerable items, out object result);
35+
36+
protected bool TryConvertElement(Type type, object value, out object result)
37+
{
38+
result = null;
39+
if (value == null)
40+
return true;
41+
42+
var valueType = value.GetType();
43+
44+
if (type.IsAssignableFrom(valueType))
45+
{
46+
result = value;
47+
return true;
48+
}
49+
50+
try
51+
{
52+
var code = System.Convert.GetTypeCode(value);
53+
54+
if (type.IsEnum)
55+
{
56+
if (value is string)
57+
{
58+
result = Enum.Parse(type, (string)value);
59+
return true;
60+
}
61+
else
62+
{
63+
result = Enum.ToObject(type, value);
64+
return true;
65+
}
66+
}
67+
else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
68+
{
69+
result = System.Convert.ChangeType(value, Nullable.GetUnderlyingType(type));
70+
return true;
71+
}
72+
else if (code != TypeCode.Object)
73+
{
74+
result = System.Convert.ChangeType(value, type);
75+
return true;
76+
}
77+
else
78+
{
79+
var data = value as IDictionary<string, object>;
80+
if (data != null)
81+
return ConcreteTypeCreator.Get(type).TryCreate(data, out result);
82+
}
83+
}
84+
catch (FormatException)
85+
{
86+
return false;
87+
}
88+
catch (ArgumentException)
89+
{
90+
return false;
91+
}
92+
93+
return true;
94+
}
95+
96+
protected bool TryConvertElements(Type type, IEnumerable items, out Array result)
97+
{
98+
result = null;
99+
List<object> list;
100+
if (items == null)
101+
list = new List<object>();
102+
else
103+
list = items.OfType<object>().ToList();
104+
105+
var array = Array.CreateInstance(type, list.Count);
106+
object element;
107+
for(var i = 0; i < array.Length; i++)
108+
{
109+
if(!TryConvertElement(type, list[i], out element))
110+
return false;
111+
array.SetValue(element, i);
112+
}
113+
114+
result = array;
115+
return true;
116+
}
117+
}
118+
119+
private class NonGenericListCreator : Creator
120+
{
121+
public override bool IsCollectionType(Type type)
122+
{
123+
if (type == typeof(string))
124+
return false;
125+
126+
return type == typeof(IEnumerable) ||
127+
type == typeof(ICollection) ||
128+
type == typeof(IList) ||
129+
type == typeof(ArrayList);
130+
}
131+
132+
public override bool TryCreate(Type type, IEnumerable items, out object result)
133+
{
134+
var list = new ArrayList(items.OfType<object>().ToList());
135+
result = list;
136+
return true;
137+
}
138+
}
139+
140+
private class GenericListCreator : Creator
141+
{
142+
private static readonly Type _openListType = typeof(List<>);
143+
144+
public override bool IsCollectionType(Type type)
145+
{
146+
if (!type.IsGenericType)
147+
return false;
148+
149+
var genericTypeDef = type.GetGenericTypeDefinition();
150+
if(genericTypeDef.GetGenericArguments().Length != 1)
151+
return false;
152+
153+
return genericTypeDef == typeof(IEnumerable<>) ||
154+
genericTypeDef == typeof(ICollection<>) ||
155+
genericTypeDef == typeof(IList<>) ||
156+
genericTypeDef == typeof(List<>);
157+
}
158+
159+
public override bool TryCreate(Type type, IEnumerable items, out object result)
160+
{
161+
result = null;
162+
var elementType = GetElementType(type);
163+
var listType = _openListType.MakeGenericType(elementType);
164+
Array elements;
165+
if (!TryConvertElements(elementType, items, out elements))
166+
return false;
167+
168+
result = Activator.CreateInstance(listType, elements);
169+
return true;
170+
}
171+
172+
private Type GetElementType(Type type)
173+
{
174+
return type.GetGenericArguments()[0];
175+
}
176+
}
177+
178+
private class GenericSetCreator : Creator
179+
{
180+
private static readonly Type _openSetType = typeof(HashSet<>);
181+
182+
public override bool IsCollectionType(Type type)
183+
{
184+
if (!type.IsGenericType)
185+
return false;
186+
187+
var genericTypeDef = type.GetGenericTypeDefinition();
188+
if (genericTypeDef.GetGenericArguments().Length != 1)
189+
return false;
190+
191+
return genericTypeDef == typeof(ISet<>) ||
192+
genericTypeDef == typeof(HashSet<>);
193+
}
194+
195+
public override bool TryCreate(Type type, IEnumerable items, out object result)
196+
{
197+
result = null;
198+
var elementType = GetElementType(type);
199+
var setType = _openSetType.MakeGenericType(elementType);
200+
Array elements;
201+
if (!TryConvertElements(elementType, items, out elements))
202+
return false;
203+
204+
result = Activator.CreateInstance(setType, elements);
205+
return true;
206+
}
207+
208+
private Type GetElementType(Type type)
209+
{
210+
return type.GetGenericArguments()[0];
211+
}
212+
}
213+
}
214+
}

Simple.Data/ConcreteTypeCreator.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Reflection;
66
using System.Text;
77
using Simple.Data.Extensions;
8+
using System.Collections;
89

910
namespace Simple.Data
1011
{
@@ -34,9 +35,24 @@ public bool TryCreate(IDictionary<string, object> data, out object result)
3435
{
3536
bool anyPropertiesSet = false;
3637
object obj = Activator.CreateInstance(_concreteType);
38+
object value;
3739
foreach (var propertyInfo in _concreteType.GetProperties().Where(pi => CanSetProperty(pi, data)))
3840
{
39-
propertyInfo.SetValue(obj, data[propertyInfo.Name], null);
41+
value = data[propertyInfo.Name.Homogenize()];
42+
43+
if (ConcreteCollectionTypeCreator.IsCollectionType(propertyInfo.PropertyType))
44+
{
45+
if (!ConcreteCollectionTypeCreator.TryCreate(propertyInfo.PropertyType, (IEnumerable)value, out value))
46+
continue;
47+
}
48+
else
49+
{
50+
var subData = value as IDictionary<string, object>;
51+
if (subData != null && !ConcreteTypeCreator.Get(propertyInfo.PropertyType).TryCreate(subData, out value))
52+
continue;
53+
}
54+
55+
propertyInfo.SetValue(obj, value, null);
4056
anyPropertiesSet = true;
4157
}
4258

0 commit comments

Comments
 (0)