Skip to content

Commit 7a2332c

Browse files
committed
Added basic Select
1 parent 6575a84 commit 7a2332c

5 files changed

Lines changed: 182 additions & 86 deletions

File tree

Simple.Data.UnitTest/DictionaryQueryRunnerTest.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Simple.Data.UnitTest
77
{
88
using NUnit.Framework;
9+
using QueryPolyfills;
910

1011
[TestFixture]
1112
public class DictionaryQueryRunnerTest
@@ -70,6 +71,28 @@ public void SkipAndTakeWithCountShouldSkipAndTakeAndGiveCount()
7071
Assert.AreEqual(1, actual[0]["Row"]);
7172
}
7273

74+
[Test]
75+
public void SelectShouldRestrictColumnList()
76+
{
77+
var tableRef = new ObjectReference("FooTable");
78+
var selectClause = new SelectClause(new SimpleReference[] { new ObjectReference("Id", tableRef), new ObjectReference("Name", tableRef) });
79+
var runner = new DictionaryQueryRunner(SelectSource(), selectClause);
80+
var actual = runner.Run().ToList();
81+
Assert.AreEqual(4, actual.Count);
82+
Assert.AreEqual(2, actual[0].Count);
83+
Assert.AreEqual(1, actual[0]["Id"]);
84+
Assert.AreEqual("Alice", actual[0]["Name"]);
85+
Assert.AreEqual(2, actual[1].Count);
86+
Assert.AreEqual(2, actual[1]["Id"]);
87+
Assert.AreEqual("Bob", actual[1]["Name"]);
88+
Assert.AreEqual(2, actual[2].Count);
89+
Assert.AreEqual(3, actual[2]["Id"]);
90+
Assert.AreEqual("Charlie", actual[2]["Name"]);
91+
Assert.AreEqual(2, actual[3].Count);
92+
Assert.AreEqual(4, actual[3]["Id"]);
93+
Assert.AreEqual("David", actual[3]["Name"]);
94+
}
95+
7396
#region Distinct sources
7497

7598
private static IEnumerable<IDictionary<string, object>> DuplicatingSource()
@@ -121,5 +144,25 @@ private static IEnumerable<IDictionary<string, object>> SkipTakeSource()
121144
}
122145

123146
#endregion
147+
148+
private static IEnumerable<IDictionary<string,object>> SelectSource()
149+
{
150+
yield return new Dictionary<string, object>
151+
{
152+
{"Id", 1}, { "Type", "A"}, {"Name","Alice"}, {"Weight", 100M}
153+
};
154+
yield return new Dictionary<string, object>
155+
{
156+
{"Id", 2}, { "Type", "A"}, {"Name","Bob"}, {"Weight", 150M}
157+
};
158+
yield return new Dictionary<string, object>
159+
{
160+
{"Id", 3}, { "Type", "B"}, {"Name","Charlie"}, {"Weight", 200M}
161+
};
162+
yield return new Dictionary<string, object>
163+
{
164+
{"Id", 4}, { "Type", "B"}, {"Name","David"}, {"Weight", 250M}
165+
};
166+
}
124167
}
125168
}

Simple.Data/DictionaryQueryRunner.cs

Lines changed: 0 additions & 85 deletions
This file was deleted.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace Simple.Data.QueryPolyfills
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
7+
public class DictionaryEqualityComparer : IEqualityComparer<IDictionary<string, object>>
8+
{
9+
public bool Equals(IDictionary<string, object> x, IDictionary<string, object> y)
10+
{
11+
if (ReferenceEquals(x, y)) return true;
12+
if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) return false;
13+
if (x.Count != y.Count) return false;
14+
object yvalue;
15+
return x.Keys.All(key => y.TryGetValue(key, out yvalue) && Equals(x[key], yvalue));
16+
}
17+
18+
public int GetHashCode(IDictionary<string, object> obj)
19+
{
20+
return obj.Aggregate(0,
21+
(acc, kvp) => (((acc * 397) ^ kvp.Key.GetHashCode()) * 397) ^ (kvp.Value ?? DBNull.Value).GetHashCode());
22+
}
23+
24+
public override int GetHashCode()
25+
{
26+
return 0;
27+
}
28+
}
29+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
namespace Simple.Data.QueryPolyfills
2+
{
3+
using System;
4+
using System.Collections.Concurrent;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
8+
internal class DictionaryQueryRunner
9+
{
10+
private static readonly
11+
Dictionary<Type, Func<SimpleQueryClauseBase, IEnumerable<IDictionary<string, object>>, IEnumerable<IDictionary<string, object>>>> ClauseHandlers =
12+
new Dictionary<Type, Func<SimpleQueryClauseBase, IEnumerable<IDictionary<string, object>>, IEnumerable<IDictionary<string, object>>>>
13+
{
14+
{ typeof(DistinctClause), (c,d) => d.Distinct(new DictionaryEqualityComparer()) },
15+
{ typeof(SkipClause), (c,d) => d.Skip(((SkipClause)c).Count) },
16+
{ typeof(TakeClause), (c,d) => d.Take(((TakeClause)c).Count) },
17+
{ typeof(SelectClause), (c,d) => new SelectClauseHandler((SelectClause)c).Run(d) },
18+
};
19+
20+
private readonly IEnumerable<IDictionary<string, object>> _source;
21+
private readonly IList<SimpleQueryClauseBase> _clauses;
22+
private readonly WithCountClause _withCountClause;
23+
24+
public DictionaryQueryRunner(IEnumerable<IDictionary<string, object>> source, IEnumerable<SimpleQueryClauseBase> clauses)
25+
{
26+
_source = source;
27+
_clauses = clauses.ToList();
28+
_withCountClause = _clauses.OfType<WithCountClause>().FirstOrDefault();
29+
if (_withCountClause != null) _clauses.Remove(_withCountClause);
30+
}
31+
32+
public DictionaryQueryRunner(IEnumerable<IDictionary<string, object>> source, params SimpleQueryClauseBase[] clauses)
33+
: this(source, clauses.AsEnumerable())
34+
{
35+
}
36+
37+
public IEnumerable<IDictionary<string, object>> Run()
38+
{
39+
IEnumerable<IDictionary<string, object>> source;
40+
if (_withCountClause != null)
41+
{
42+
source = _source.ToList();
43+
_withCountClause.SetCount(source.Count());
44+
}
45+
else
46+
{
47+
source = _source;
48+
}
49+
50+
foreach (var clause in _clauses)
51+
{
52+
Func<SimpleQueryClauseBase, IEnumerable<IDictionary<string, object>>, IEnumerable<IDictionary<string, object>>> handler;
53+
if (ClauseHandlers.TryGetValue(clause.GetType(), out handler))
54+
{
55+
source = handler(clause, source);
56+
}
57+
}
58+
59+
return source;
60+
}
61+
}
62+
63+
class SelectClauseHandler
64+
{
65+
private readonly IList<SimpleReference> _references;
66+
private readonly IList<ObjectReference> _objectReferences;
67+
private Func<int, IDictionary<string, object>> _creator;
68+
69+
public SelectClauseHandler(SelectClause clause)
70+
{
71+
_references = clause.Columns.ToList();
72+
_objectReferences = _references.Select(r => r as ObjectReference).ToList();
73+
}
74+
75+
public IEnumerable<IDictionary<string,object>> Run(IEnumerable<IDictionary<string,object>> source)
76+
{
77+
return source.Select(Run);
78+
}
79+
80+
private IDictionary<string,object> Run(IDictionary<string,object> source)
81+
{
82+
if (_creator == null) _creator = CreateCreator(source);
83+
var target = _creator(_references.Count);
84+
for (int i = 0; i < _objectReferences.Count; i++)
85+
{
86+
if (!ReferenceEquals(_objectReferences[i], null))
87+
{
88+
var name = _objectReferences[i].GetName();
89+
target[name] = source[name];
90+
}
91+
}
92+
return target;
93+
}
94+
95+
private Func<int, IDictionary<string, object>> CreateCreator(IDictionary<string,object> source)
96+
{
97+
var dictionary = source as Dictionary<string, object>;
98+
if (dictionary != null) return cap => new Dictionary<string, object>(cap, dictionary.Comparer);
99+
var sortedDictionary = source as SortedDictionary<string, object>;
100+
if (sortedDictionary != null) return cap => new SortedDictionary<string, object>(sortedDictionary.Comparer);
101+
var concurrentDictionary = source as ConcurrentDictionary<string, object>;
102+
if (concurrentDictionary != null) return cap => new ConcurrentDictionary<string, object>();
103+
104+
var type = source.GetType();
105+
return cap => (IDictionary<string, object>) Activator.CreateInstance(type);
106+
}
107+
}
108+
}

Simple.Data/Simple.Data.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@
7878
<Compile Include="Database.Open.cs" />
7979
<Compile Include="DatabaseOpenerMethods.cs" />
8080
<Compile Include="DictionaryCloner.cs" />
81-
<Compile Include="DictionaryQueryRunner.cs" />
81+
<Compile Include="QueryPolyfills\DictionaryEqualityComparer.cs" />
82+
<Compile Include="QueryPolyfills\DictionaryQueryRunner.cs" />
8283
<Compile Include="DistinctClause.cs" />
8384
<Compile Include="EnumerableEx.cs" />
8485
<Compile Include="ExistsSpecialReference.cs" />

0 commit comments

Comments
 (0)