diff --git a/PoweredSoft.DynamicLinq.Test/CountTests.cs b/PoweredSoft.DynamicLinq.Test/CountTests.cs new file mode 100644 index 0000000..6dbba3d --- /dev/null +++ b/PoweredSoft.DynamicLinq.Test/CountTests.cs @@ -0,0 +1,28 @@ +using System; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace PoweredSoft.DynamicLinq.Test +{ + [TestClass] + public class CountTests + { + [TestMethod] + public void Count() + { + var normalSyntax = TestData.Sales.Count(); + var nonGenericQueryable = (IQueryable)TestData.Sales.AsQueryable(); + var dynamicSyntax = nonGenericQueryable.Count(); + Assert.AreEqual(normalSyntax, dynamicSyntax); + } + + [TestMethod] + public void LongCount() + { + var normalSyntax = TestData.Sales.LongCount(); + var nonGenericQueryable = (IQueryable)TestData.Sales.AsQueryable(); + var dynamicSyntax = nonGenericQueryable.LongCount(); + Assert.AreEqual(normalSyntax, dynamicSyntax); + } + } +} diff --git a/PoweredSoft.DynamicLinq.Test/EntityFrameworkTests.cs b/PoweredSoft.DynamicLinq.Test/EntityFrameworkTests.cs index 0f4fffc..363c2d9 100644 --- a/PoweredSoft.DynamicLinq.Test/EntityFrameworkTests.cs +++ b/PoweredSoft.DynamicLinq.Test/EntityFrameworkTests.cs @@ -14,7 +14,8 @@ namespace PoweredSoft.DynamicLinq.Test public class EntityFrameworkTests { public static string testConnectionString => - "data source=(local); initial catalog=blogtests;persist security info=True; Integrated Security=SSPI;"; + @"Server=(localdb)\mssqllocaldb;Database=EFProviders.InMemory;Trusted_Connection=True;"; + //"data source=(local); initial catalog=blogtests;persist security info=True; Integrated Security=SSPI;"; public static void SeedForTests(BlogContext context) { diff --git a/PoweredSoft.DynamicLinq.Test/GroupingTests.cs b/PoweredSoft.DynamicLinq.Test/GroupingTests.cs index 56246c0..9c694cf 100644 --- a/PoweredSoft.DynamicLinq.Test/GroupingTests.cs +++ b/PoweredSoft.DynamicLinq.Test/GroupingTests.cs @@ -32,6 +32,34 @@ namespace PoweredSoft.DynamicLinq.Test [TestClass] public class GroupingTests { + [TestMethod] + public void TestEmptyGroup() + { + var subject = TestData.Sales; + + var normalSyntax = subject + .GroupBy(t => true) + .Select(t => new + { + NetSalesSum = t.Sum(t2 => t2.NetSales), + NetSalesAvg = t.Average(t2 => t2.NetSales) + }) + .First(); + + var dynamicSyntax = subject + .EmptyGroupBy(typeof(MockSale)) + .Select(sb => + { + sb.Sum("NetSales", "NetSalesSum"); + sb.Average("NetSales", "NetSalesAvg"); + }) + .ToDynamicClassList() + .First(); + + Assert.AreEqual(normalSyntax.NetSalesAvg, dynamicSyntax.GetDynamicPropertyValue("NetSalesAvg")); + Assert.AreEqual(normalSyntax.NetSalesSum, dynamicSyntax.GetDynamicPropertyValue("NetSalesSum")); + } + [TestMethod] public void WantedSyntax() { @@ -75,5 +103,51 @@ namespace PoweredSoft.DynamicLinq.Test QueryableAssert.AreEqual(left.Sales.AsQueryable(), right.GetDynamicPropertyValue>("Sales").AsQueryable()); } } + + [TestMethod] + public void TestingSelectBuilderAggregateFluent() + { + var normalSyntax = TestData.Sales + .GroupBy(t => new { t.ClientId }) + .Select(t => new + { + TheClientId = t.Key.ClientId, + Count = t.Count(), + LongCount = t.LongCount(), + NetSales = t.Sum(t2 => t2.NetSales), + TaxAverage = t.Average(t2 => t2.Tax), + Sales = t.ToList() + }) + .ToList(); + + var dynamicSyntax = TestData.Sales + .AsQueryable() + .GroupBy(t => t.Path("ClientId")) + .Select(t => + { + t.Aggregate("Key.ClientId", SelectTypes.Key, "TheClientId"); + // should not have to specify a path, but a property is a must + t.Aggregate(null, SelectTypes.Count, "Count"); + // support both ways it can use path to guess property so testing this too + t.Aggregate("LongCount", SelectTypes.LongCount); + t.Aggregate("NetSales", SelectTypes.Sum); + t.Aggregate("Tax", SelectTypes.Average, "TaxAverage"); + t.ToList("Sales"); + }) + .ToDynamicClassList(); + + Assert.AreEqual(normalSyntax.Count, dynamicSyntax.Count); + for (var i = 0; i < normalSyntax.Count; i++) + { + var left = normalSyntax[i]; + var right = dynamicSyntax[i]; + + Assert.AreEqual(left.TheClientId, right.GetDynamicPropertyValue("TheClientId")); + Assert.AreEqual(left.Count, right.GetDynamicPropertyValue("Count")); + Assert.AreEqual(left.LongCount, right.GetDynamicPropertyValue("LongCount")); + Assert.AreEqual(left.TaxAverage, right.GetDynamicPropertyValue("TaxAverage")); + QueryableAssert.AreEqual(left.Sales.AsQueryable(), right.GetDynamicPropertyValue>("Sales").AsQueryable()); + } + } } } diff --git a/PoweredSoft.DynamicLinq.Test/PoweredSoft.DynamicLinq.Test.csproj b/PoweredSoft.DynamicLinq.Test/PoweredSoft.DynamicLinq.Test.csproj index 7a858b8..707be9c 100644 --- a/PoweredSoft.DynamicLinq.Test/PoweredSoft.DynamicLinq.Test.csproj +++ b/PoweredSoft.DynamicLinq.Test/PoweredSoft.DynamicLinq.Test.csproj @@ -77,6 +77,7 @@ + diff --git a/PoweredSoft.DynamicLinq/Extensions/EnumerableExtensions.cs b/PoweredSoft.DynamicLinq/Extensions/EnumerableExtensions.cs index 993844a..a605253 100644 --- a/PoweredSoft.DynamicLinq/Extensions/EnumerableExtensions.cs +++ b/PoweredSoft.DynamicLinq/Extensions/EnumerableExtensions.cs @@ -47,6 +47,9 @@ namespace PoweredSoft.DynamicLinq public static IQueryable GroupBy(this IEnumerable list, Type type, Action callback) => list.AsQueryable().GroupBy(type, callback); + public static IQueryable EmptyGroupBy(this IEnumerable list, Type underlyingType) + => list.AsQueryable().EmptyGroupBy(underlyingType); + public static List Reversed(this List list) { var copy = list.ToList(); diff --git a/README.md b/README.md index b0680a0..d56afd9 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Shortcuts allow to avoid specifying the condition operator by having it handy in ```csharp queryable.Query(t => t.Contains("FirstName", "Dav").OrContains("FirstName", "Jo")); ``` -You may visit this test for more examples: https://github.com/PoweredSoft/DynamicLinq/blob/master/PoweredSoft.DynamicLinq.Test/ShortcutTests.cs +> You may visit this test for more examples: https://github.com/PoweredSoft/DynamicLinq/blob/master/PoweredSoft.DynamicLinq.Test/ShortcutTests.cs ### Simple Query ```csharp @@ -51,10 +51,11 @@ TestData.Sales t.LongCount("LongCount"); t.Sum("NetSales"); t.Average("Tax", "TaxAverage"); + t.Aggregate("Tax", SelectTypes.Average, "TaxAverage2"); // Starting 1.0.5 t.ToList("Sales"); }); ``` -Is equivalent to +> Is equivalent to ```csharp TestSales .GroupBy(t => new { t.ClientId }) @@ -64,10 +65,38 @@ TestSales LongCount = t.LongCount(), NetSales = t.Sum(t2 => t2.NetSales), TaxAverage = t.Average(t2 => t2.Tax), + TaxAverage2 = t.Average(t2 => t2.Tax), Sales = t.ToList() }); ``` +### Empty Group By + +This is common to create aggregate totals. + +```csharp +someQueryable.EmptyGroupBy(typeof(SomeClass)); +``` +> Is equivalent to + +```csharp +someQueryableOfT.GroupBy(t => true); +``` + +### Count shortcut + +```csharp +IQueryable someQueryable = ; +someQueryable.Count(); +``` + +> Is equivalent to + +```csharp +IQueryable someQueryableOfT = ; +someQsomeQueryableOfTueryable.Count(); +``` + ### Select ```csharp