Permalink
Browse files

Fixed issue with SimpleQuery joins... it was complicated.

  • Loading branch information...
1 parent 927cc4c commit bd4d0f40cd64c10f7b7d9e20e0402968d21a54c4 @markrendle committed Dec 4, 2012
View
26 Simple.Data.InMemoryTest/InMemoryTests.cs
@@ -697,5 +697,31 @@ public void JoinTest()
Assert.That(detail.Id, Is.EqualTo(masterId));
Assert.That(detail.Box, Is.EqualTo(999));
}
+
+ [Test]
+ public void LeftJoinTest()
+ {
+ var adapter = new InMemoryAdapter();
+ adapter.SetKeyColumn("Events", "Id");
+ adapter.SetAutoIncrementColumn("Events", "Id");
+ adapter.SetKeyColumn("Doors", "Id");
+ adapter.SetAutoIncrementColumn("Doors", "Id");
+ adapter.Join.Master("Events", "Id").Detail("Doors", "EventId");
+ Database.UseMockAdapter(adapter);
+ var db = Database.Open();
+ db.Events.Insert(Id: 1, Code: "CodeMash2013", Name: "CodeMash 2013");
+ db.Events.Insert(Id: 2, Code: "SomewhereElse", Name: "Some Other Conf");
+ db.Doors.Insert(Id: 1, Code: "F7E08AC9-5E75-417D-A7AA-60E88B5B99AD", EventID: 1);
+ db.Doors.Insert(Id: 2, Code: "0631C802-2748-4C63-A6D9-CE8C803002EB", EventID: 1);
+ db.Doors.Insert(Id: 3, Code: "281ED88F-677D-49B9-84FA-4FAE022BBC73", EventID: 1);
+ db.Doors.Insert(Id: 4, Code: "9DF7E964-1ECE-42E3-8211-1F2BF7054A0D", EventID: 2);
+ db.Doors.Insert(Id: 5, Code: "9418123D-312A-4E8C-8807-59F0A63F43B9", EventID: 2);
+
+ List<dynamic> actual = db.Doors.FindAll(db.Doors.Events.Code == "CodeMash2013")
+ .Select(db.Doors.Id, db.Events.Name)
+ .ToList();
+
+ Assert.AreEqual(3, actual.Count);
+ }
}
}
View
40 Simple.Data.UnitTest/DictionaryQueryRunnerTest.cs
@@ -14,7 +14,7 @@ public class DictionaryQueryRunnerTest
[Test]
public void DistinctShouldRemoveDuplicateRows()
{
- var runner = new DictionaryQueryRunner(DuplicatingSource(), new DistinctClause());
+ var runner = new DictionaryQueryRunner("FooTable", DuplicatingSource(), new DistinctClause());
var actual = runner.Run().ToList();
Assert.AreEqual(2, actual.Count);
Assert.AreEqual(1, actual.Count(d => d.ContainsKey("Foo") && (string)d["Foo"] == "bar"));
@@ -24,7 +24,7 @@ public void DistinctShouldRemoveDuplicateRows()
[Test]
public void ShouldNotRemoveDistinctRows()
{
- var runner = new DictionaryQueryRunner(NonDuplicatingSource(), new DistinctClause());
+ var runner = new DictionaryQueryRunner("FooTable", NonDuplicatingSource(), new DistinctClause());
var actual = runner.Run().ToList();
Assert.AreEqual(2, actual.Count);
Assert.AreEqual(1, actual.Count(d => d.ContainsKey("Foo") && (string)d["Foo"] == "bar"));
@@ -34,7 +34,7 @@ public void ShouldNotRemoveDistinctRows()
[Test]
public void SkipShouldSkip()
{
- var runner = new DictionaryQueryRunner(SkipTakeSource(), new SkipClause(1));
+ var runner = new DictionaryQueryRunner("FooTable", SkipTakeSource(), new SkipClause(1));
var actual = runner.Run().ToList();
Assert.AreEqual(2, actual.Count);
Assert.AreEqual(1, actual[0]["Row"]);
@@ -44,7 +44,7 @@ public void SkipShouldSkip()
[Test]
public void TakeShouldTake()
{
- var runner = new DictionaryQueryRunner(SkipTakeSource(), new TakeClause(2));
+ var runner = new DictionaryQueryRunner("FooTable", SkipTakeSource(), new TakeClause(2));
var actual = runner.Run().ToList();
Assert.AreEqual(2, actual.Count);
Assert.AreEqual(0, actual[0]["Row"]);
@@ -54,7 +54,7 @@ public void TakeShouldTake()
[Test]
public void SkipAndTakeShouldSkipAndTake()
{
- var runner = new DictionaryQueryRunner(SkipTakeSource(), new SkipClause(1), new TakeClause(1));
+ var runner = new DictionaryQueryRunner("FooTable", SkipTakeSource(), new SkipClause(1), new TakeClause(1));
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual(1, actual[0]["Row"]);
@@ -64,7 +64,7 @@ public void SkipAndTakeShouldSkipAndTake()
public void SkipAndTakeWithCountShouldSkipAndTakeAndGiveCount()
{
int count = 0;
- var runner = new DictionaryQueryRunner(SkipTakeSource(), new WithCountClause(n => count = n), new SkipClause(1), new TakeClause(1));
+ var runner = new DictionaryQueryRunner("FooTable", SkipTakeSource(), new WithCountClause(n => count = n), new SkipClause(1), new TakeClause(1));
var actual = runner.Run().ToList();
Assert.AreEqual(3, count);
Assert.AreEqual(1, actual.Count);
@@ -76,7 +76,7 @@ public void SelectShouldRestrictColumnList()
{
var tableRef = new ObjectReference("FooTable");
var selectClause = new SelectClause(new SimpleReference[] { new ObjectReference("Id", tableRef), new ObjectReference("Name", tableRef) });
- var runner = new DictionaryQueryRunner(SelectSource(), selectClause);
+ var runner = new DictionaryQueryRunner("FooTable", SelectSource(), selectClause);
var actual = runner.Run().ToList();
Assert.AreEqual(4, actual.Count);
Assert.AreEqual(2, actual[0].Count);
@@ -99,7 +99,7 @@ public void SelectLengthShouldUseLengthFunction()
var tableRef = new ObjectReference("FooTable");
var function = new FunctionReference("Length", new ObjectReference("Name", tableRef)).As("NameLength");
var selectClause = new SelectClause(new SimpleReference[] { new ObjectReference("Name", tableRef), function });
- var runner = new DictionaryQueryRunner(SelectSource(), selectClause);
+ var runner = new DictionaryQueryRunner("FooTable", SelectSource(), selectClause);
var actual = runner.Run().ToList();
Assert.AreEqual(4, actual.Count);
Assert.AreEqual(2, actual[0].Count);
@@ -121,7 +121,7 @@ public void BasicWhereEqualShouldWork()
{
var tableRef = new ObjectReference("FooTable");
var whereClause = new WhereClause(new ObjectReference("Name", tableRef) == "Alice");
- var runner = new DictionaryQueryRunner(SelectSource(), whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", SelectSource(), whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual("Alice", actual[0]["Name"]);
@@ -143,7 +143,7 @@ public void WhereNullShouldWorkWhenValueExistsAndIsNull()
{"Name", "Dave"}, { "Value", 42 }
},
};
- var runner = new DictionaryQueryRunner(data, whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", data, whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual("Steve", actual[0]["Name"]);
@@ -165,7 +165,7 @@ public void WhereNullShouldWorkWhenValueDoesNotExist()
{"Name", "Dave"}, { "Value", 42 }
},
};
- var runner = new DictionaryQueryRunner(data, whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", data, whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual("Steve", actual[0]["Name"]);
@@ -187,7 +187,7 @@ public void WhereEqualWithByteArrayShouldWork()
{"Name", "Dave"}, { "Array", new byte[] { 2, 3, 4}}
},
};
- var runner = new DictionaryQueryRunner(data, whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", data, whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual("Steve", actual[0]["Name"]);
@@ -198,7 +198,7 @@ public void BasicWhereNotEqualShouldWork()
{
var tableRef = new ObjectReference("FooTable");
var whereClause = new WhereClause(new ObjectReference("Name", tableRef) != "Alice");
- var runner = new DictionaryQueryRunner(SelectSource(), whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", SelectSource(), whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(3, actual.Count);
Assert.False(actual.Any(a => (string)a["Name"] == "Alice"));
@@ -220,7 +220,7 @@ public void WhereNotNullShouldWork()
{"Name", "Dave"}, { "Value", 42 }
},
};
- var runner = new DictionaryQueryRunner(data, whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", data, whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual("Dave", actual[0]["Name"]);
@@ -242,7 +242,7 @@ public void WhereNotEqualWithByteArrayShouldWork()
{"Name", "Dave"}, { "Array", new byte[] { 2, 3, 4}}
},
};
- var runner = new DictionaryQueryRunner(data, whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", data, whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual("Dave", actual[0]["Name"]);
@@ -253,7 +253,7 @@ public void BasicWhereGreaterThanShouldWork()
{
var tableRef = new ObjectReference("FooTable");
var whereClause = new WhereClause(new ObjectReference("Weight", tableRef) > 200M);
- var runner = new DictionaryQueryRunner(SelectSource(), whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", SelectSource(), whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual("David", actual[0]["Name"]);
@@ -264,7 +264,7 @@ public void BasicWhereLessThanShouldWork()
{
var tableRef = new ObjectReference("FooTable");
var whereClause = new WhereClause(new ObjectReference("Weight", tableRef) < 150M);
- var runner = new DictionaryQueryRunner(SelectSource(), whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", SelectSource(), whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual("Alice", actual[0]["Name"]);
@@ -275,7 +275,7 @@ public void BasicWhereGreaterThanOrEqualShouldWork()
{
var tableRef = new ObjectReference("FooTable");
var whereClause = new WhereClause(new ObjectReference("Weight", tableRef) >= 250M);
- var runner = new DictionaryQueryRunner(SelectSource(), whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", SelectSource(), whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual("David", actual[0]["Name"]);
@@ -286,7 +286,7 @@ public void BasicWhereLessThanOrEqualShouldWork()
{
var tableRef = new ObjectReference("FooTable");
var whereClause = new WhereClause(new ObjectReference("Weight", tableRef) <= 100M);
- var runner = new DictionaryQueryRunner(SelectSource(), whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", SelectSource(), whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual("Alice", actual[0]["Name"]);
@@ -299,7 +299,7 @@ public void BasicLikeShouldWork()
dynamic objRef = new ObjectReference("Name", tableRef);
var expression = new SimpleExpression(objRef, new SimpleFunction("like", new[] {"A%"}), SimpleExpressionType.Function);
var whereClause = new WhereClause(expression);
- var runner = new DictionaryQueryRunner(SelectSource(), whereClause);
+ var runner = new DictionaryQueryRunner("FooTable", SelectSource(), whereClause);
var actual = runner.Run().ToList();
Assert.AreEqual(1, actual.Count);
Assert.AreEqual("Alice", actual[0]["Name"]);
View
2 Simple.Data/InMemoryAdapter.cs
@@ -64,7 +64,7 @@ public override IList<string> GetKeyNames(string tableName)
public override IEnumerable<IDictionary<string, object>> Find(string tableName, SimpleExpression criteria)
{
- var whereClauseHandler = new WhereClauseHandler(new WhereClause(criteria));
+ var whereClauseHandler = new WhereClauseHandler(tableName, new WhereClause(criteria));
return whereClauseHandler.Run(GetTable(tableName));
}
View
12 Simple.Data/QueryPolyfills/DictionaryQueryRunner.cs
@@ -17,20 +17,22 @@ private static readonly
{ typeof(OrderByClause), (c, d) => new OrderByClauseHandler((OrderByClause)c).Run(d) }
};
+ private readonly string _mainTableName;
private readonly IEnumerable<IDictionary<string, object>> _source;
private readonly IList<SimpleQueryClauseBase> _clauses;
private readonly WithCountClause _withCountClause;
- public DictionaryQueryRunner(IEnumerable<IDictionary<string, object>> source, IEnumerable<SimpleQueryClauseBase> clauses)
+ public DictionaryQueryRunner(string mainTableName, IEnumerable<IDictionary<string, object>> source, IEnumerable<SimpleQueryClauseBase> clauses)
{
+ _mainTableName = mainTableName;
_source = source;
_clauses = clauses.ToList();
_withCountClause = _clauses.OfType<WithCountClause>().FirstOrDefault();
if (_withCountClause != null) _clauses.Remove(_withCountClause);
}
- public DictionaryQueryRunner(IEnumerable<IDictionary<string, object>> source, params SimpleQueryClauseBase[] clauses)
- : this(source, clauses.AsEnumerable())
+ public DictionaryQueryRunner(string mainTableName, IEnumerable<IDictionary<string, object>> source, params SimpleQueryClauseBase[] clauses)
+ : this(mainTableName, source, clauses.AsEnumerable())
{
}
@@ -63,7 +65,7 @@ public DictionaryQueryRunner(IEnumerable<IDictionary<string, object>> source, pa
{
foreach (var whereClause in _clauses.OfType<WhereClause>())
{
- source = new WhereClauseHandler(whereClause).Run(source);
+ source = new WhereClauseHandler(_mainTableName, whereClause).Run(source);
}
return source;
}
@@ -99,7 +101,7 @@ public DictionaryQueryRunner(IEnumerable<IDictionary<string, object>> source, pa
{
var criteria = HavingToWhere(clause.Criteria, selectReferences);
source = new SelectClauseHandler(new SelectClause(selectReferences)).Run(source).ToList();
- source = new WhereClauseHandler(new WhereClause(criteria)).Run(source);
+ source = new WhereClauseHandler(_mainTableName, new WhereClause(criteria)).Run(source);
source = source.Select(d => d.Where(kvp => !kvp.Key.StartsWith(AutoColumnPrefix)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value));
}
View
20 Simple.Data/QueryPolyfills/WhereClauseHandler.cs
@@ -5,15 +5,18 @@ namespace Simple.Data.QueryPolyfills
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
+ using Extensions;
internal class WhereClauseHandler
{
private readonly Dictionary<SimpleExpressionType, Func<SimpleExpression, Func<IDictionary<string, object>, bool>>> _expressionFormatters;
+ private readonly string _mainTableName;
private readonly WhereClause _whereClause;
- public WhereClauseHandler(WhereClause whereClause)
+ public WhereClauseHandler(string mainTableName, WhereClause whereClause)
{
+ _mainTableName = mainTableName;
_whereClause = whereClause;
_expressionFormatters = new Dictionary<SimpleExpressionType, Func<SimpleExpression, Func<IDictionary<string, object>, bool>>>
{
@@ -147,6 +150,21 @@ private IList<object> Resolve(IDictionary<string, object> dict, object operand,
return ResolveSubs(dict, objectReference.GetOwner(), key).ToList();
}
+ if (keys.Length == 2 && !HomogenizedEqualityComparer.DefaultInstance.Equals(keys[0].Singularize(), _mainTableName.Singularize()))
+ {
+ var joinedDict = dict[keys[0]] as IDictionary<string, object>;
+ if (joinedDict != null && joinedDict.ContainsKey(keys[1]))
+ {
+ return new[] { joinedDict[keys[1]] };
+ }
+
+ var joinedDicts = dict[keys[0]] as IEnumerable<IDictionary<string, object>>;
+ if (joinedDicts != null)
+ {
+ return joinedDicts.Select(d => d.ContainsKey(keys[1]) ? d[keys[1]] : null).ToArray();
+ }
+ }
+
if (dict.ContainsKey(key))
return new[] { dict[key] };
View
59 Simple.Data/SimpleQuery.cs
@@ -312,7 +312,7 @@ protected IEnumerable<dynamic> Run()
var unhandledClausesList = unhandledClauses.ToList();
if (unhandledClausesList.Count > 0)
{
- result = new DictionaryQueryRunner(result, unhandledClausesList).Run();
+ result = new DictionaryQueryRunner(_tableName, result, unhandledClausesList).Run();
}
}
@@ -511,6 +511,55 @@ public SimpleQuery OuterJoin(ObjectReference objectReference, out dynamic queryO
return this;
}
+ public SimpleQuery Join(DynamicTable dynamicTable, JoinType joinType)
+ {
+ if (ReferenceEquals(dynamicTable, null)) throw new ArgumentNullException("dynamicTable");
+ _tempJoinWaitingForOn = new JoinClause(dynamicTable.ToObjectReference(), joinType, null);
+
+ return this;
+ }
+
+ public SimpleQuery Join(DynamicTable dynamicTable, out dynamic queryObjectReference)
+ {
+ return Join(dynamicTable, JoinType.Inner, out queryObjectReference);
+ }
+
+ public SimpleQuery Join(DynamicTable dynamicTable, JoinType joinType, out dynamic queryObjectReference)
+ {
+ if (ReferenceEquals(dynamicTable, null)) throw new ArgumentNullException("dynamicTable");
+ var newJoin = new JoinClause(dynamicTable.ToObjectReference(), null);
+ _tempJoinWaitingForOn = newJoin;
+ queryObjectReference = dynamicTable.ToObjectReference();
+
+ return this;
+ }
+
+ public SimpleQuery LeftJoin(DynamicTable dynamicTable)
+ {
+ return OuterJoin(dynamicTable);
+ }
+
+ public SimpleQuery LeftJoin(DynamicTable dynamicTable, out dynamic queryObjectReference)
+ {
+ return OuterJoin(dynamicTable, out queryObjectReference);
+ }
+
+ public SimpleQuery OuterJoin(DynamicTable dynamicTable)
+ {
+ if (ReferenceEquals(dynamicTable, null)) throw new ArgumentNullException("dynamicTable");
+ _tempJoinWaitingForOn = new JoinClause(dynamicTable.ToObjectReference(), JoinType.Outer);
+
+ return this;
+ }
+
+ public SimpleQuery OuterJoin(DynamicTable dynamicTable, out dynamic queryObjectReference)
+ {
+ _tempJoinWaitingForOn = new JoinClause(dynamicTable.ToObjectReference(), JoinType.Outer);
+ queryObjectReference = dynamicTable;
+
+ return this;
+ }
+
public SimpleQuery On(SimpleExpression joinExpression)
{
if (_tempJoinWaitingForOn == null)
@@ -542,6 +591,14 @@ public SimpleQuery WithTotalCount(out Promise<int> count)
private SimpleQuery ParseJoin(InvokeMemberBinder binder, object[] args)
{
var tableToJoin = args[0] as ObjectReference;
+ if (ReferenceEquals(tableToJoin, null))
+ {
+ var dynamicTable = args[0] as DynamicTable;
+ if (!ReferenceEquals(dynamicTable, null))
+ {
+ tableToJoin = dynamicTable.ToObjectReference();
+ }
+ }
if (tableToJoin == null) throw new InvalidOperationException();
SimpleExpression joinExpression = null;

0 comments on commit bd4d0f4

Please sign in to comment.