Skip to content

Commit 66a2692

Browse files
committed
Aggregates working in InMemory adapter
1 parent cb6782c commit 66a2692

18 files changed

Lines changed: 392 additions & 79 deletions

Simple.Data.Ado/Joiner.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public IEnumerable<string> GetJoinClauses(IEnumerable<JoinClause> joins, IComman
6868
var builder = new StringBuilder(JoinKeyword);
6969
builder.AppendFormat(" JOIN {0}{1} ON ({2})",
7070
_schema.FindTable(ObjectName.Parse(join.Table.ToString())).QualifiedName,
71-
string.IsNullOrWhiteSpace(join.Table.Alias) ? string.Empty : " " + _schema.QuoteObjectName(join.Table.Alias),
71+
string.IsNullOrWhiteSpace(join.Table.GetAlias()) ? string.Empty : " " + _schema.QuoteObjectName(join.Table.GetAlias()),
7272
expressionFormatter.Format(join.JoinExpression));
7373
yield return builder.ToString().Trim();
7474
}

Simple.Data.Ado/SimpleReferenceFormatter.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,13 @@ private string TryFormatAsFunctionReference(FunctionReference functionReference)
6868
if (ReferenceEquals(functionReference, null)) return null;
6969

7070
var sqlName = _functionNameConverter.ConvertToSqlName(functionReference.Name);
71-
return functionReference.Alias == null
71+
return functionReference.GetAlias() == null
7272
? string.Format("{0}({1}{2})", sqlName,
7373
FormatColumnClause(functionReference.Argument),
7474
FormatAdditionalArguments(functionReference.AdditionalArguments))
7575
: string.Format("{0}({1}) AS {2}", sqlName,
7676
FormatColumnClause(functionReference.Argument),
77-
_schema.QuoteObjectName(functionReference.Alias));
77+
_schema.QuoteObjectName(functionReference.GetAlias()));
7878
}
7979

8080
private string FormatAdditionalArguments(IEnumerable<object> additionalArguments)
@@ -93,15 +93,15 @@ private string TryFormatAsObjectReference(ObjectReference objectReference)
9393
if (ReferenceEquals(objectReference, null)) return null;
9494

9595
var table = _schema.FindTable(objectReference.GetOwner().GetAllObjectNamesDotted());
96-
var tableName = string.IsNullOrWhiteSpace(objectReference.GetOwner().Alias)
96+
var tableName = string.IsNullOrWhiteSpace(objectReference.GetOwner().GetAlias())
9797
? table.QualifiedName
98-
: _schema.QuoteObjectName(objectReference.GetOwner().Alias);
98+
: _schema.QuoteObjectName(objectReference.GetOwner().GetAlias());
9999
var column = table.FindColumn(objectReference.GetName());
100-
if (objectReference.Alias == null)
100+
if (objectReference.GetAlias() == null)
101101
return string.Format("{0}.{1}", tableName, column.QuotedName);
102102
else
103103
return string.Format("{0}.{1} AS {2}", tableName, column.QuotedName,
104-
_schema.QuoteObjectName(objectReference.Alias));
104+
_schema.QuoteObjectName(objectReference.GetAlias()));
105105
}
106106

107107
}

Simple.Data.InMemoryTest/InMemoryTests.cs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,37 @@ public void AllShouldReturnAllRecords()
4848
Assert.AreEqual(2, records.Count);
4949
}
5050

51+
[Test]
52+
public void SelectShouldReturnSubsetOfColumns()
53+
{
54+
Database.UseMockAdapter(new InMemoryAdapter());
55+
var db = Database.Open();
56+
db.Test.Insert(Id: 1, Name: "Alice");
57+
db.Test.Insert(Id: 2, Name: "Bob");
58+
List<IDictionary<string,object>> records = db.Test.All().Select(db.Test.Name).ToList<IDictionary<string,object>>();
59+
Assert.IsNotNull(records);
60+
Assert.AreEqual(2, records.Count);
61+
Assert.False(records[0].ContainsKey("Id"));
62+
Assert.True(records[0].ContainsKey("Name"));
63+
Assert.False(records[1].ContainsKey("Id"));
64+
Assert.True(records[1].ContainsKey("Name"));
65+
}
66+
67+
[Test]
68+
public void SelectWithAggregateShouldReturnAggregates()
69+
{
70+
Database.UseMockAdapter(new InMemoryAdapter());
71+
var db = Database.Open();
72+
db.Test.Insert(Id: 1, Name: "Alice", Age: 20);
73+
db.Test.Insert(Id: 2, Name: "Alice", Age: 30);
74+
db.Test.Insert(Id: 3, Name: "Bob", Age: 40);
75+
db.Test.Insert(Id: 4, Name: "Bob", Age: 50);
76+
var records = db.Test.All().Select(db.Test.Name, db.Test.Age.Average().As("AverageAge")).ToList();
77+
Assert.AreEqual(2, records.Count);
78+
Assert.AreEqual(25, records[0].AverageAge);
79+
Assert.AreEqual(45, records[1].AverageAge);
80+
}
81+
5182
[Test]
5283
public void ShouldWorkWithByteArrays()
5384
{
@@ -83,6 +114,63 @@ public void TestDeleteBy()
83114
Assert.IsNull(record);
84115
}
85116

117+
[Test]
118+
public void TestOrderBy()
119+
{
120+
Database.UseMockAdapter(new InMemoryAdapter());
121+
var db = Database.Open();
122+
for (int i = 0; i < 10; i++)
123+
{
124+
db.Test.Insert(Id: i, Name: "Alice");
125+
}
126+
127+
var records = db.Test.All().OrderByIdDescending().ToList();
128+
Assert.AreEqual(9, records[0].Id);
129+
}
130+
131+
[Test]
132+
public void TestSkip()
133+
{
134+
Database.UseMockAdapter(new InMemoryAdapter());
135+
var db = Database.Open();
136+
for (int i = 0; i < 10; i++)
137+
{
138+
db.Test.Insert(Id: i, Name: "Alice");
139+
}
140+
141+
var records = db.Test.All().Skip(5).ToList();
142+
Assert.AreEqual(5, records.Count);
143+
}
144+
145+
[Test]
146+
public void TestTake()
147+
{
148+
Database.UseMockAdapter(new InMemoryAdapter());
149+
var db = Database.Open();
150+
for (int i = 0; i < 10; i++)
151+
{
152+
db.Test.Insert(Id: i, Name: "Alice");
153+
}
154+
155+
var records = db.Test.All().Take(5).ToList();
156+
Assert.AreEqual(5, records.Count);
157+
}
158+
159+
[Test]
160+
public void TestSkipAndTake()
161+
{
162+
Database.UseMockAdapter(new InMemoryAdapter());
163+
var db = Database.Open();
164+
for (int i = 0; i < 10; i++)
165+
{
166+
db.Test.Insert(Id: i, Name: "Alice");
167+
}
168+
169+
var records = db.Test.All().OrderByIdDescending().Skip(1).Take(1).ToList();
170+
Assert.AreEqual(1, records.Count);
171+
Assert.AreEqual(8, records[0].Id);
172+
}
173+
86174
/// <summary>
87175
///A test for Find
88176
///</summary>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using NUnit.Framework;
6+
using Simple.Data.QueryPolyfills;
7+
8+
namespace Simple.Data.UnitTest
9+
{
10+
[TestFixture]
11+
class GroupingHandlerTest
12+
{
13+
[Test]
14+
public void GroupingOnSingleKeyWorks()
15+
{
16+
var source = new List<IDictionary<string, object>>
17+
{
18+
new Dictionary<string, object> {{"Id", 1}, {"Size", 1}},
19+
new Dictionary<string, object> {{"Id", 1}, {"Size", 2}},
20+
new Dictionary<string, object> {{"Id", 1}, {"Size", 3}},
21+
new Dictionary<string, object> {{"Id", 2}, {"Size", 4}},
22+
new Dictionary<string, object> {{"Id", 2}, {"Size", 5}},
23+
new Dictionary<string, object> {{"Id", 2}, {"Size", 6}},
24+
};
25+
var target = new GroupingHandler("Id");
26+
var actual = target.Group(source).ToList();
27+
Assert.AreEqual(2, actual.Count);
28+
}
29+
[Test]
30+
public void GroupingOnDoubleKeyWorks()
31+
{
32+
var source = new List<IDictionary<string, object>>
33+
{
34+
new Dictionary<string, object> {{"Id", 1}, {"Type", "A"}, {"Size", 1}},
35+
new Dictionary<string, object> {{"Id", 1}, {"Type", "A"}, {"Size", 2}},
36+
new Dictionary<string, object> {{"Id", 1}, {"Type", "B"}, {"Size", 3}},
37+
new Dictionary<string, object> {{"Id", 1}, {"Type", "B"}, {"Size", 4}},
38+
new Dictionary<string, object> {{"Id", 2}, {"Type", "A"}, {"Size", 5}},
39+
new Dictionary<string, object> {{"Id", 2}, {"Type", "A"}, {"Size", 6}},
40+
new Dictionary<string, object> {{"Id", 2}, {"Type", "B"}, {"Size", 7}},
41+
new Dictionary<string, object> {{"Id", 2}, {"Type", "B"}, {"Size", 8}},
42+
};
43+
var target = new GroupingHandler("Id", "Type");
44+
var actual = target.Group(source).ToList();
45+
Assert.AreEqual(4, actual.Count);
46+
}
47+
}
48+
}

Simple.Data.UnitTest/Simple.Data.UnitTest.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
<Compile Include="DynamicReferenceTest.cs" />
7777
<Compile Include="DynamicTableTest.cs" />
7878
<Compile Include="ExpressionHelperTest.cs" />
79+
<Compile Include="GroupingHandlerTest.cs" />
7980
<Compile Include="PromiseTest.cs" />
8081
<Compile Include="ListHelper.cs" />
8182
<Compile Include="MathReferenceTest.cs" />

Simple.Data/FunctionReference.cs

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ public class FunctionReference : SimpleReference, IEquatable<FunctionReference>
2121
private readonly SimpleReference _argument;
2222
private readonly object[] _additionalArguments;
2323
private readonly bool _isAggregate;
24-
private readonly string _alias;
2524

2625
internal FunctionReference(string name, SimpleReference argument, params object[] additionalArguments)
2726
{
@@ -31,12 +30,11 @@ internal FunctionReference(string name, SimpleReference argument, params object[
3130
_isAggregate = AggregateFunctionNames.Contains(name.ToLowerInvariant());
3231
}
3332

34-
private FunctionReference(string name, SimpleReference argument, bool isAggregate, string alias, params object[] additionalArguments)
33+
private FunctionReference(string name, SimpleReference argument, bool isAggregate, string alias, params object[] additionalArguments) : base(alias)
3534
{
3635
_name = name;
3736
_argument = argument;
3837
_isAggregate = isAggregate;
39-
_alias = alias;
4038
_additionalArguments = additionalArguments;
4139
}
4240

@@ -50,18 +48,9 @@ public FunctionReference As(string alias)
5048
return new FunctionReference(_name, _argument, _isAggregate, alias);
5149
}
5250

53-
public string Alias
51+
public override string GetAliasOrName()
5452
{
55-
get { return _alias; }
56-
}
57-
58-
/// <summary>
59-
/// Gets the name of the referenced object.
60-
/// </summary>
61-
/// <returns>The name.</returns>
62-
public string GetAliasOrName()
63-
{
64-
return _alias ?? _name;
53+
return GetAlias() ?? _name;
6554
}
6655

6756
public bool IsAggregate
@@ -161,7 +150,7 @@ public bool Equals(FunctionReference other)
161150
{
162151
if (ReferenceEquals(null, other)) return false;
163152
if (ReferenceEquals(this, other)) return true;
164-
return Equals(other._name, _name) && Equals(other._argument, _argument) && other._isAggregate.Equals(_isAggregate) && Equals(other._alias, _alias);
153+
return Equals(other._name, _name) && Equals(other._argument, _argument) && other._isAggregate.Equals(_isAggregate) && Equals(other.GetAlias(), GetAlias());
165154
}
166155

167156
public override bool Equals(object obj)
@@ -179,7 +168,7 @@ public override int GetHashCode()
179168
int result = (_name != null ? _name.GetHashCode() : 0);
180169
result = (result*397) ^ (_argument != null ? _argument.GetHashCode() : 0);
181170
result = (result*397) ^ _isAggregate.GetHashCode();
182-
result = (result*397) ^ (_alias != null ? _alias.GetHashCode() : 0);
171+
result = (result*397) ^ (GetAlias() != null ? GetAlias().GetHashCode() : 0);
183172
return result;
184173
}
185174
}

Simple.Data/JoinClause.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public ObjectReference Table
3232

3333
public string Name
3434
{
35-
get { return _table.Alias ?? _table.GetName(); }
35+
get { return _table.GetAlias() ?? _table.GetName(); }
3636
}
3737
}
3838
}

Simple.Data/ObjectReference.cs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ public class ObjectReference : SimpleReference, IEquatable<ObjectReference>
1616
private readonly string _name;
1717
private readonly ObjectReference _owner;
1818
private readonly DataStrategy _dataStrategy;
19-
private readonly string _alias;
2019

2120
internal ObjectReference(string name) : this(name, null, null, null)
2221
{
@@ -30,17 +29,11 @@ internal ObjectReference(string name, DataStrategy dataStrategy) : this(name, nu
3029
{
3130
}
3231

33-
internal ObjectReference(string name, ObjectReference owner, DataStrategy dataStrategy, string alias)
32+
internal ObjectReference(string name, ObjectReference owner, DataStrategy dataStrategy, string alias) : base(alias)
3433
{
3534
_name = name;
3635
_owner = owner;
3736
_dataStrategy = dataStrategy;
38-
_alias = alias;
39-
}
40-
41-
public string Alias
42-
{
43-
get { return _alias; }
4437
}
4538

4639
/// <summary>
@@ -71,18 +64,14 @@ public string GetName()
7164
return _name;
7265
}
7366

74-
/// <summary>
75-
/// Gets the name of the referenced object.
76-
/// </summary>
77-
/// <returns>The name.</returns>
78-
public string GetAliasOrName()
67+
public ObjectReference As(string alias)
7968
{
80-
return _alias ?? _name;
69+
return new ObjectReference(_name, _owner, _dataStrategy, alias);
8170
}
8271

83-
public ObjectReference As(string alias)
72+
public override string GetAliasOrName()
8473
{
85-
return new ObjectReference(_name, _owner, _dataStrategy, alias);
74+
return GetAlias() ?? _name;
8675
}
8776

8877
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
@@ -321,5 +310,10 @@ public override string ToString()
321310
{
322311
return new MathReference(column, value, MathOperator.Modulo);
323312
}
313+
314+
public bool HasOwner()
315+
{
316+
return !ReferenceEquals(null, _owner);
317+
}
324318
}
325319
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace Simple.Data.QueryPolyfills
6+
{
7+
internal class AggregateValueResolver : ValueResolver
8+
{
9+
private readonly FunctionReference _reference;
10+
private readonly ValueResolver _argumentResolver;
11+
private readonly Func<IEnumerable<object>, object> _handler;
12+
13+
public AggregateValueResolver(FunctionReference reference)
14+
{
15+
_reference = reference;
16+
_argumentResolver = Create(reference.Argument);
17+
_handler = FunctionHandlers.Get(reference.Name);
18+
}
19+
20+
public override void CopyValue(IDictionary<string, object> source, IDictionary<string, object> target,
21+
IEnumerable<IDictionary<string, object>> sourceAggregationValues = null)
22+
{
23+
target[_reference.GetAliasOrName()] = GetValue(source, sourceAggregationValues);
24+
}
25+
26+
public override object GetValue(IDictionary<string, object> source, IEnumerable<IDictionary<string, object>> sourceAggregationValues = null)
27+
{
28+
if (sourceAggregationValues == null) throw new ArgumentNullException("sourceAggregationValues");
29+
return _handler(sourceAggregationValues.Select(d => _argumentResolver.GetValue(d)));
30+
}
31+
}
32+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
7+
namespace Simple.Data.QueryPolyfills
8+
{
9+
class DictionaryCreatorFactory
10+
{
11+
public static Func<int, IDictionary<string, object>> CreateFunc(IDictionary<string, object> source)
12+
{
13+
var dictionary = source as Dictionary<string, object>;
14+
if (dictionary != null) return cap => new Dictionary<string, object>(cap, dictionary.Comparer);
15+
var sortedDictionary = source as SortedDictionary<string, object>;
16+
if (sortedDictionary != null) return cap => new SortedDictionary<string, object>(sortedDictionary.Comparer);
17+
if (source is ConcurrentDictionary<string,object>) return cap => new ConcurrentDictionary<string, object>();
18+
19+
var type = source.GetType();
20+
return cap => (IDictionary<string, object>) Activator.CreateInstance(type);
21+
}
22+
}
23+
}

0 commit comments

Comments
 (0)