Skip to content

Commit

Permalink
Next- v2.4.6 (#54)
Browse files Browse the repository at this point in the history
* update ordering description

* update packages

* Lazy map generation. performance improvement

* benchmark lazy map generation

* remove public access to fixMapper method

* update to v2.4.6

* update library comparision benchmark result

* fix spelling mistake

* AddMap always throw exception

* check IgnoreNotMappedFields in fixMapper
  • Loading branch information
alirezanet authored Dec 10, 2021
1 parent def0ecb commit 6171d25
Show file tree
Hide file tree
Showing 20 changed files with 334 additions and 114 deletions.
6 changes: 3 additions & 3 deletions benchmark/Benchmark.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.0" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
<PackageReference Include="Fop" Version="1.0.1.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.DynamicLinq" Version="5.2.10" />
<PackageReference Include="Sieve" Version="2.4.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.DynamicLinq" Version="6.2.14" />
<PackageReference Include="Sieve" Version="2.5.1" />
</ItemGroup>

<ItemGroup>
Expand Down
149 changes: 149 additions & 0 deletions benchmark/GridifyMapperUsages.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using BenchmarkDotNet.Order;
using Gridify;
using Gridify.Tests;

namespace Benchmarks
{
[MemoryDiagnoser]
[RPlotExporter]
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
public class GridifyMapperUsages
{
private static readonly Consumer Consumer = new();
private TestClass[] _data;
private Func<TestClass, bool> compiled1;
private Func<TestClass, bool> compiled2;
private Func<TestClass, bool> compiled3;

private IQueryable<TestClass> Ds => _data.AsQueryable();
private IEnumerable<TestClass> EnumerableDs => _data.ToList();
private IGridifyMapper<TestClass> ggm { get; set; }

[GlobalSetup]
public void Setup()
{
_data = GetSampleData().ToArray();

ggm = new GridifyMapper<TestClass>().GenerateMappings();

// compiled query (this is not included in our readme benchmarks)
var gq1 = new GridifyQuery() { Filter = "Name=*a" };
var gq2 = new GridifyQuery() { Filter = "Id>5" };
var gq3 = new GridifyQuery() { Filter = "Name=Ali" };
compiled1 = gq1.GetFilteringExpression(ggm).Compile();
compiled2 = gq2.GetFilteringExpression(ggm).Compile();
compiled3 = gq3.GetFilteringExpression(ggm).Compile();
}


[Benchmark(Baseline = true)]
public void NativeLinQ()
{
Ds.Where(q => q.Name.Contains("a")).Consume(Consumer);
Ds.Where(q => q.Id > 5).Consume(Consumer);
Ds.Where(q => q.Name == "Ali").Consume(Consumer);
}
[Benchmark]
public void Gridify_GlobalMapper()
{
Ds.ApplyFiltering("Name=*a", ggm).Consume(Consumer);
Ds.ApplyFiltering("Id>5", ggm).Consume(Consumer);
Ds.ApplyFiltering("Name=Ali", ggm).Consume(Consumer);
}
[Benchmark]
public void Gridify_SingleMapper_Generated()
{
var gm = new GridifyMapper<TestClass>().GenerateMappings();
Ds.ApplyFiltering("Name=*a", gm).Consume(Consumer);
Ds.ApplyFiltering("Id>5", gm).Consume(Consumer);
Ds.ApplyFiltering("Name=Ali", gm).Consume(Consumer);
}

[Benchmark]
public void Gridify_SingleMapper_Manual()
{
var gm = new GridifyMapper<TestClass>()
.AddMap("name")
.AddMap("id");

Ds.ApplyFiltering("Name=*a", gm).Consume(Consumer);
Ds.ApplyFiltering("Id>5", gm).Consume(Consumer);
Ds.ApplyFiltering("Name=Ali", gm).Consume(Consumer);
}

[Benchmark]
public void Gridify_NoMapper()
{
Ds.ApplyFiltering("Name=*a").Consume(Consumer);
Ds.ApplyFiltering("Id>5").Consume(Consumer);
Ds.ApplyFiltering("Name=Ali").Consume(Consumer);
}
[Benchmark]
public void Gridify_EachAction_Generated()
{
Ds.ApplyFiltering("Name=*a", new GridifyMapper<TestClass>().GenerateMappings()).Consume(Consumer);
Ds.ApplyFiltering("Id>5", new GridifyMapper<TestClass>().GenerateMappings()).Consume(Consumer);
Ds.ApplyFiltering("Name=Ali", new GridifyMapper<TestClass>().GenerateMappings()).Consume(Consumer);
}

// [Benchmark]
// public void GridifyCompiled()
// {
// EnumerableDs.Where(compiled1).Consume(Consumer);
// EnumerableDs.Where(compiled2).Consume(Consumer);
// EnumerableDs.Where(compiled3).Consume(Consumer);
// }

public static IEnumerable<TestClass> GetSampleData()
{
var lst = new List<TestClass>();
lst.Add(new TestClass(1, "John", null, Guid.NewGuid(), DateTime.Now));
lst.Add(new TestClass(2, "Bob", null, Guid.NewGuid(), DateTime.UtcNow));
lst.Add(new TestClass(3, "Jack", (TestClass)lst[0].Clone(), Guid.Empty, DateTime.Now.AddDays(2)));
lst.Add(new TestClass(4, "Rose", null, Guid.Parse("e2cec5dd-208d-4bb5-a852-50008f8ba366")));
lst.Add(new TestClass(5, "Ali", null));
lst.Add(new TestClass(6, "Hamid", (TestClass)lst[0].Clone(), Guid.Parse("de12bae1-93fa-40e4-92d1-2e60f95b468c")));
lst.Add(new TestClass(7, "Hasan", (TestClass)lst[1].Clone()));
lst.Add(new TestClass(8, "Farhad", (TestClass)lst[2].Clone(), Guid.Empty));
lst.Add(new TestClass(9, "Sara", null));
lst.Add(new TestClass(10, "Jorge", null));
lst.Add(new TestClass(11, "joe", null));
lst.Add(new TestClass(12, "jimmy", (TestClass)lst[0].Clone()));
lst.Add(new TestClass(13, "Nazanin", null));
lst.Add(new TestClass(14, "Reza", null));
lst.Add(new TestClass(15, "Korosh", (TestClass)lst[0].Clone()));
lst.Add(new TestClass(16, "Kamran", (TestClass)lst[1].Clone()));
lst.Add(new TestClass(17, "Saeid", (TestClass)lst[2].Clone()));
lst.Add(new TestClass(18, "jessi==ca", null));
lst.Add(new TestClass(19, "Ped=ram", null));
lst.Add(new TestClass(20, "Peyman!", null));
lst.Add(new TestClass(21, "Fereshte", null));
lst.Add(new TestClass(22, "LIAM", null));
lst.Add(new TestClass(22, @"\Liam", null));
lst.Add(new TestClass(23, "LI | AM", null));
lst.Add(new TestClass(24, "(LI,AM)", null));
return lst;
}
}
}

// BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
// 11th Gen Intel Core i5-11400F 2.60GHz, 1 CPU, 12 logical and 6 physical cores
// .NET SDK=6.0.100
// [Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
// DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
//
//
// | Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Allocated |
// |------------------------------- |---------:|---------:|---------:|------:|--------:|-------:|-------:|----------:|
// | NativeLinQ | 826.9 us | 13.49 us | 12.61 us | 1.00 | 0.00 | 4.8828 | 1.9531 | 35 KB |
// | Gridify_SingleMapper_Manual | 846.4 us | 8.64 us | 7.66 us | 1.02 | 0.02 | 5.8594 | 2.9297 | 41 KB |
// | Gridify_SingleMapper_Generated | 847.8 us | 10.72 us | 9.51 us | 1.02 | 0.02 | 6.8359 | 2.9297 | 43 KB |
// | Gridify_GlobalMapper | 854.6 us | 15.35 us | 19.42 us | 1.04 | 0.03 | 5.8594 | 2.9297 | 40 KB |
// | Gridify_NoMapper | 876.5 us | 17.33 us | 28.48 us | 1.07 | 0.04 | 5.8594 | 1.9531 | 44 KB |
// | Gridify_EachAction_Generated | 877.4 us | 16.82 us | 20.66 us | 1.06 | 0.03 | 7.8125 | 3.9063 | 48 KB |
56 changes: 16 additions & 40 deletions benchmark/LibraryComparisionFilteringBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,55 +22,33 @@ public class LibraryComparisionFilteringBenchmark
{
private static readonly Consumer Consumer = new();
private TestClass[] _data;
private Func<TestClass, bool> compiled1;
private Func<TestClass, bool> compiled2;
private Func<TestClass, bool> compiled3;

private IQueryable<TestClass> Ds => _data.AsQueryable();
private IEnumerable<TestClass> EnumerableDs => _data.ToList();
private IGridifyMapper<TestClass> gm { get; set; }

[GlobalSetup]
public void Setup()
{
_data = GetSampleData().ToArray();

gm = new GridifyMapper<TestClass>().GenerateMappings();

// compiled query (this is not included in our readme benchmarks)
var gq1 = new GridifyQuery() { Filter = "Name=*a" };
var gq2 = new GridifyQuery() { Filter = "Id>5" };
var gq3 = new GridifyQuery() { Filter = "Name=Ali" };
compiled1 = gq1.GetFilteringExpression(gm).Compile();
compiled2 = gq2.GetFilteringExpression(gm).Compile();
compiled3 = gq3.GetFilteringExpression(gm).Compile();
}


[Benchmark(Baseline = true)]
public void NativeLinQ()
{
Ds.Where(q => q.Name.Contains("a")).Consume(Consumer);
Ds.Where(q => q.Name.Contains('a')).Consume(Consumer);
Ds.Where(q => q.Id > 5).Consume(Consumer);
Ds.Where(q => q.Name == "Ali").Consume(Consumer);
}

[Benchmark]
public void Gridify()
{
var gm = new GridifyMapper<TestClass>().GenerateMappings();
Ds.ApplyFiltering("Name=*a", gm).Consume(Consumer);
Ds.ApplyFiltering("Id>5", gm).Consume(Consumer);
Ds.ApplyFiltering("Name=Ali", gm).Consume(Consumer);
}

// [Benchmark] // compiled query (this is not included in our readme benchmarks)w
public void GridifyCompiled()
{
EnumerableDs.Where(compiled1).Consume(Consumer);
EnumerableDs.Where(compiled2).Consume(Consumer);
EnumerableDs.Where(compiled3).Consume(Consumer);
}

[Benchmark]
public void Fop()
{
Expand Down Expand Up @@ -131,19 +109,17 @@ public static IEnumerable<TestClass> GetSampleData()
}
}

/* Last Run:
BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19043.1237 (21H1/May2021Update)
11th Gen Intel Core i5-11400F 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK=5.0.301
[Host] : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT
DefaultJob : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT
| Method | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Allocated |
|------------ |-----------:|---------:|---------:|------:|--------:|--------:|----------:|
| Native LINQ | 740.9 us | 7.80 us | 6.92 us | 1.00 | 5.8594 | 2.9297 | 37 KB |
| Gridify | 762.6 us | 10.06 us | 9.41 us | 1.03 | 5.8594 | 2.9297 | 39 KB |
| DynamicLinq | 902.1 us | 11.56 us | 10.81 us | 1.22 | 19.5313 | 9.7656 | 122 KB |
| Sieve | 977.9 us | 6.80 us | 6.37 us | 1.32 | 7.8125 | 3.9063 | 54 KB |
| Fop | 2,959.8 us | 39.11 us | 36.58 us | 3.99 | 46.8750 | 23.4375 | 306 KB |
*/
// BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
// 11th Gen Intel Core i5-11400F 2.60GHz, 1 CPU, 12 logical and 6 physical cores
// .NET SDK=6.0.100
// [Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
// DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
//
//
// | Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Allocated |
// |------------ |-----------:|---------:|---------:|------:|--------:|--------:|--------:|----------:|
// | NativeLinQ | 823.8 us | 11.18 us | 9.91 us | 1.00 | 0.00 | 4.8828 | 1.9531 | 35 KB |
// | Gridify | 853.1 us | 13.88 us | 12.98 us | 1.03 | 0.02 | 6.8359 | 2.9297 | 43 KB |
// | DynamicLinQ | 967.3 us | 6.65 us | 5.55 us | 1.17 | 0.01 | 19.5313 | 9.7656 | 123 KB |
// | Sieve | 1,275.2 us | 5.62 us | 4.70 us | 1.55 | 0.02 | 7.8125 | 3.9063 | 55 KB |
// | Fop | 3,480.2 us | 55.81 us | 52.21 us | 4.23 | 0.06 | 54.6875 | 27.3438 | 343 KB |
1 change: 1 addition & 0 deletions benchmark/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class Program
private static void Main()
{
BenchmarkRunner.Run<LibraryComparisionFilteringBenchmark>();
// BenchmarkRunner.Run<GridifyMapperUsages>();
// BenchmarkRunner.Run<QueryBuilderBuildBenchmark>();
// BenchmarkRunner.Run<QueryBuilderEvaluatorBenchmark>();
Console.Read();
Expand Down
22 changes: 11 additions & 11 deletions docs/guide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ Be sure to check out these examples
Filtering is the most expensive feature in gridify. the following benchmark is comparing filtering in the most known dynamic linq libraries. As you can see, gridify has the closest result to the native linq.


| Method | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Allocated |
|------------ |-----------:|---------:|---------:|------:|--------:|--------:|----------:|
| Native LINQ | 740.9 us | 7.80 us | 6.92 us | 1.00 | 5.8594 | 2.9297 | 37 KB |
| **Gridify*** | 762.6 us | 10.06 us | 9.41 us | 1.03 | 5.8594 | 2.9297 | 39 KB |
| DynamicLinq | 902.1 us | 11.56 us | 10.81 us | 1.22 | 19.5313 | 9.7656 | 122 KB |
| Sieve | 977.9 us | 6.80 us | 6.37 us | 1.32 | 7.8125 | 3.9063 | 54 KB |
| Fop | 2,959.8 us | 39.11 us | 36.58 us | 3.99 | 46.8750 | 23.4375 | 306 KB |
| Method | Mean | Error | Ratio | Gen 0 | Gen 1 | Allocated |
|------------ |-----------:|---------:|------:|--------:|--------:|----------:|
| NativeLinQ | 823.8 us | 11.18 us | 1.00 | 4.8828 | 1.9531 | 35 KB |
| ***Gridify** | 853.1 us | 13.88 us | **1.03** | 6.8359 | 2.9297 | 43 KB |
| DynamicLinQ | 967.3 us | 6.65 us | 1.17 | 19.5313 | 9.7656 | 123 KB |
| Sieve | 1,275.2 us | 5.62 us | 1.55 | 7.8125 | 3.9063 | 55 KB |
| Fop | 3,480.2 us | 55.81 us | 4.23 | 54.6875 | 27.3438 | 343 KB |

::: details
BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19043.1237 (21H1/May2021Update)
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
11th Gen Intel Core i5-11400F 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK=5.0.301
[Host] : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT
DefaultJob : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT
.NET SDK=6.0.100
[Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
:::
2 changes: 0 additions & 2 deletions docs/guide/autoMapper.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ Gridify library does not have a built-in GridifyTo extension method because we d
public static Paging<TDestination> GridifyTo<TSource, TDestination>(this IQueryable<TSource> query,
IMapper autoMapper, IGridifyQuery gridifyQuery, IGridifyMapper<TSource> mapper = null)
{
mapper = mapper.FixMapper();
var res = query.GridifyQueryable(gridifyQuery, mapper);
return new Paging<TDestination> (res.Count , res.Query.ProjectTo<TDestination>(autoMapper.ConfigurationProvider).ToList());
}
Expand All @@ -34,7 +33,6 @@ public static Paging<TDestination> GridifyTo<TSource, TDestination>(this IQuerya
public static async Task<Paging<TDestination>> GridifyToAsync<TSource, TDestination>(this IQueryable<TSource> query,
IMapper autoMapper, IGridifyQuery gridifyQuery, IGridifyMapper<TSource> mapper = null)
{
mapper = mapper.FixMapper();
var res = await query.GridifyQueryableAsync(gridifyQuery, mapper);
return new Paging<TDestination> (res.Count , await res.Query.ProjectTo<TDestination>(autoMapper.ConfigurationProvider).ToListAsync());
}
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/filtering.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ this query matches with JOHN - john - John - jOHn ...

## Escaping

Gridify have five special operators `, | ( ) /i` to handle complex queries and case-insensitive searchs. If you want to use these characters in your query values (after conditional operator), you should add a backslash <code>\ </code> before them. having this regex could be helpfull `([(),|]|\/i)`.
Gridify have five special operators `, | ( ) /i` to handle complex queries and case-insensitive searches. If you want to use these characters in your query values (after conditional operator), you should add a backslash <code>\ </code> before them. having this regex could be helpfull `([(),|]|\/i)`.

JavaScript escape example:
``` javascript
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
export default {
setup() {
return {
version: '2.4.5'
version: '2.4.6'
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/ordering.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Ordering Syntax

The ordering query expression can be built with a comma-separated field names followed by **`asc`** or **`desc`** keywords.
The ordering query expression can be built with a comma-delimited ordered list of field/property names followed by **`asc`** or **`desc`** keywords.

by default, if you don't add these keywords, gridify assumes you need Ascending ordering.

Expand Down
2 changes: 1 addition & 1 deletion src/Gridify.EntityFramework/Gridify.EntityFramework.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Gridify.EntityFramework</PackageId>
<Version>2.4.5</Version>
<Version>2.4.6</Version>
<Authors>Alireza Sabouri</Authors>
<Company>TuxTeam</Company>
<PackageDescription>Gridify (EntityFramework), Easy and optimized way to apply Filtering, Sorting, and Pagination using text-based data.</PackageDescription>
Expand Down
15 changes: 7 additions & 8 deletions src/Gridify.EntityFramework/GridifyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ public async static Task<QueryablePaging<T>> GridifyQueryableAsync<T>(this IQuer

public static async Task<Paging<T>> GridifyAsync<T>(this IQueryable<T> query, IGridifyQuery gridifyQuery, IGridifyMapper<T> mapper = null)
{
mapper = mapper.FixMapper();
var res = await query.GridifyQueryableAsync(gridifyQuery, mapper);
return new Paging<T>(res.Count, await res.Query.ToListAsync());
var (count, queryable) = await query.GridifyQueryableAsync(gridifyQuery, mapper);
return new Paging<T>(count, await queryable.ToListAsync());
}

public async static Task<QueryablePaging<T>> GridifyQueryableAsync<T>(this IQueryable<T> query, IGridifyQuery gridifyQuery,
Expand All @@ -36,13 +35,13 @@ public async static Task<QueryablePaging<T>> GridifyQueryableAsync<T>(this IQuer
return new QueryablePaging<T>(count, query);
}

public static async Task<Paging<T>> GridifyAsync<T>(this IQueryable<T> query, IGridifyQuery gridifyQuery, CancellationToken token, IGridifyMapper<T> mapper = null)
public static async Task<Paging<T>> GridifyAsync<T>(this IQueryable<T> query, IGridifyQuery gridifyQuery, CancellationToken token,
IGridifyMapper<T> mapper = null)
{
mapper = mapper.FixMapper();
var res = await query.GridifyQueryableAsync(gridifyQuery, mapper, token);
return new Paging<T>(res.Count, await res.Query.ToListAsync(token));
var (count, queryable) = await query.GridifyQueryableAsync(gridifyQuery, mapper, token);
return new Paging<T>(count, await queryable.ToListAsync(token));
}

#endregion
}
}
}
2 changes: 1 addition & 1 deletion src/Gridify/Gridify.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Gridify</PackageId>
<Version>2.4.5</Version>
<Version>2.4.6</Version>
<Authors>Alireza Sabouri</Authors>
<Company>TuxTeam</Company>
<PackageDescription>Gridify, Easy and optimized way to apply Filtering, Sorting, and Pagination using text-based data.</PackageDescription>
Expand Down
Loading

0 comments on commit 6171d25

Please sign in to comment.