From 888e3ab57e569f24c96a7196275a283ec1e11334 Mon Sep 17 00:00:00 2001 From: Peter Lavallee Date: Fri, 3 Mar 2017 16:33:38 -0800 Subject: [PATCH] Add a WasEver extension to support the Ever query verb --- src/Qwiq.Linq/QueryExtensions.cs | 5 ++++ src/Qwiq.Linq/Qwiq.Linq.csproj | 1 + src/Qwiq.Linq/Visitors/QueryRewriter.cs | 8 +++++++ .../WiqlExpressions/WasEverExpression.cs | 23 +++++++++++++++++++ .../WiqlExpressions/WiqlExpressionType.cs | 3 ++- src/Qwiq.Linq/WiqlTranslator.cs | 15 ++++++++++++ test/Qwiq.Linq.Tests/QueryBuilderTests.cs | 18 +++++++++++++++ 7 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/Qwiq.Linq/WiqlExpressions/WasEverExpression.cs diff --git a/src/Qwiq.Linq/QueryExtensions.cs b/src/Qwiq.Linq/QueryExtensions.cs index 86622198..c51b7c45 100644 --- a/src/Qwiq.Linq/QueryExtensions.cs +++ b/src/Qwiq.Linq/QueryExtensions.cs @@ -18,6 +18,11 @@ private static bool AsOf(this T _, DateTime __) { return true; } + + public static bool WasEver(this T _, T __) + { + return true; + } } } diff --git a/src/Qwiq.Linq/Qwiq.Linq.csproj b/src/Qwiq.Linq/Qwiq.Linq.csproj index c5aed866..2d667938 100644 --- a/src/Qwiq.Linq/Qwiq.Linq.csproj +++ b/src/Qwiq.Linq/Qwiq.Linq.csproj @@ -258,6 +258,7 @@ + diff --git a/src/Qwiq.Linq/Visitors/QueryRewriter.cs b/src/Qwiq.Linq/Visitors/QueryRewriter.cs index 81dfe9e8..3053c865 100644 --- a/src/Qwiq.Linq/Visitors/QueryRewriter.cs +++ b/src/Qwiq.Linq/Visitors/QueryRewriter.cs @@ -71,6 +71,14 @@ protected override Expression VisitMethodCall(MethodCallExpression node) return new UnderExpression(node.Type, subject, target); } + if (node.Method.DeclaringType == typeof(QueryExtensions) && node.Method.Name == "WasEver") + { + var subject = Visit(node.Arguments[0]); + var target = Visit(node.Arguments[1]); + + return new WasEverExpression(node.Type, subject, target); + } + // This is a contains used to see if a value is in a list, such as: bug => aliases.Contains(bug.AssignedTo) if (node.Method.DeclaringType == typeof(Enumerable) && node.Method.Name == "Contains") { diff --git a/src/Qwiq.Linq/WiqlExpressions/WasEverExpression.cs b/src/Qwiq.Linq/WiqlExpressions/WasEverExpression.cs new file mode 100644 index 00000000..c9abe4cf --- /dev/null +++ b/src/Qwiq.Linq/WiqlExpressions/WasEverExpression.cs @@ -0,0 +1,23 @@ +using System; +using System.Linq.Expressions; + +namespace Microsoft.Qwiq.Linq.WiqlExpressions +{ + public class WasEverExpression : Expression + { + internal WasEverExpression(Type type, Expression subject, Expression target) + { + Type = type; + Subject = subject; + Target = target; + } + + public override ExpressionType NodeType => (ExpressionType)WiqlExpressionType.WasEver; + + public override Type Type { get; } + + internal Expression Subject { get; private set; } + internal Expression Target { get; private set; } + } +} + diff --git a/src/Qwiq.Linq/WiqlExpressions/WiqlExpressionType.cs b/src/Qwiq.Linq/WiqlExpressions/WiqlExpressionType.cs index 20e0c9dc..959cc673 100644 --- a/src/Qwiq.Linq/WiqlExpressions/WiqlExpressionType.cs +++ b/src/Qwiq.Linq/WiqlExpressions/WiqlExpressionType.cs @@ -9,7 +9,8 @@ internal enum WiqlExpressionType AsOf, Contains, Select, - Indexer + Indexer, + WasEver } } diff --git a/src/Qwiq.Linq/WiqlTranslator.cs b/src/Qwiq.Linq/WiqlTranslator.cs index fbe4777f..ce71025e 100644 --- a/src/Qwiq.Linq/WiqlTranslator.cs +++ b/src/Qwiq.Linq/WiqlTranslator.cs @@ -92,6 +92,8 @@ public override Expression Visit(Expression expression) return VisitContains((ContainsExpression)expression); case WiqlExpressionType.Indexer: return VisitIndexer((IndexerExpression) expression); + case WiqlExpressionType.WasEver: + return VisitWasEver((WasEverExpression)expression); default: return base.Visit(expression); } @@ -150,6 +152,19 @@ protected virtual Expression VisitUnder(UnderExpression expression) return expression; } + protected virtual Expression VisitWasEver(WasEverExpression expression) + { + _expressionInProgress.Enqueue(new GroupStartFragment()); + Visit(expression.Subject); + + _expressionInProgress.Enqueue(new StringFragment(" EVER ")); + + Visit(expression.Target); + _expressionInProgress.Enqueue(new GroupEndFragment()); + + return expression; + } + protected virtual Expression VisitOrder(OrderExpression expression) { Visit(expression.Source); diff --git a/test/Qwiq.Linq.Tests/QueryBuilderTests.cs b/test/Qwiq.Linq.Tests/QueryBuilderTests.cs index b5a2f1f1..6bb8f691 100644 --- a/test/Qwiq.Linq.Tests/QueryBuilderTests.cs +++ b/test/Qwiq.Linq.Tests/QueryBuilderTests.cs @@ -325,6 +325,24 @@ public void the_StartsWith_is_translated_to_an_under_operator() } } + [TestClass] + // ReSharper disable once InconsistentNaming + public class when_a_where_clause_uses_the_ever_function : QueryBuilderTests + { + public override void When() + { + base.When(); + Expected = "SELECT * FROM WorkItems WHERE (([Assigned To] EVER 'alias'))"; + Actual = Query.Where(item => item.AssignedTo.WasEver("alias")).ToString(); + } + + [TestMethod] + public void the_WasEver_is_translated_to_an_ever_operator() + { + Actual.ShouldEqual(Expected); + } + } + [TestClass] // ReSharper disable once InconsistentNaming public class when_a_where_clause_uses_the_Contains_string_function : QueryBuilderTests