From 6e6f179552c1d3025037e17cbb7114c33098b030 Mon Sep 17 00:00:00 2001
From: AliReZa Sabouri <7004080+alirezanet@users.noreply.github.com>
Date: Tue, 14 Dec 2021 10:35:52 +0330
Subject: [PATCH] Next (v2.4.7) (#57)
* Add new overload for ApplyPaging with page and pageSize
* update to 2.4.7
* fix warning declared but never used
* use file scope namespace
* add Microsoft.CodeAnalysis.CSharp.Scripting Benchmark
* add comments for setup parts
* add link to the benchmark class
* change gridify benchmark row color
* Add IsValid - fix #48
* fix IsValid example
* add invalid filter example
---
benchmark/Benchmark.csproj | 1 +
benchmark/GridifyMapperUsages.cs | 219 ++-
.../LibraryComparisionFilteringBenchmark.cs | 223 ++-
benchmark/Program.cs | 21 +-
benchmark/QueryBuilderBuildBenchmark.cs | 145 +-
benchmark/QueryBuilderEvaluatorBenchmark.cs | 65 +-
benchmark/TestClass.cs | 57 +-
docs/contribution/README.md | 15 +-
docs/guide/README.md | 31 +-
docs/guide/getting-started.md | 1 +
docs/guide/gridifyQuery.md | 37 +
docs/guide/queryBuilder.md | 1 +
.../Gridify.EntityFramework.csproj | 2 +-
src/Gridify/GMap.cs | 39 +-
src/Gridify/Gridify.csproj | 2 +-
src/Gridify/GridifyExtensions.cs | 889 +++++----
src/Gridify/GridifyFilteringException.cs | 9 +-
src/Gridify/GridifyMapper.cs | 287 ++-
src/Gridify/GridifyMapperConfiguration.cs | 33 +-
src/Gridify/GridifyMapperException.cs | 13 +-
src/Gridify/GridifyOrderingException.cs | 9 +-
src/Gridify/GridifyQuery.cs | 33 +-
src/Gridify/GridifyQueryException.cs | 13 +-
src/Gridify/IGMap.cs | 15 +-
src/Gridify/IGridifyFiltering.cs | 11 +-
src/Gridify/IGridifyMapper.cs | 37 +-
src/Gridify/IGridifyOrdering.cs | 9 +-
src/Gridify/IGridifyPagination.cs | 11 +-
src/Gridify/IGridifyQuery.cs | 7 +-
src/Gridify/IQueryBuilder.cs | 441 ++---
src/Gridify/Paging.cs | 39 +-
src/Gridify/PredicateBuilder.cs | 77 +-
src/Gridify/QueryBuilder.cs | 490 ++---
src/Gridify/QueryablePaging.cs | 31 +-
src/Gridify/Syntax/BinaryExpressionSyntax.cs | 37 +-
src/Gridify/Syntax/ExpressionSyntax.cs | 7 +-
src/Gridify/Syntax/FieldExpressionSyntax.cs | 41 +-
src/Gridify/Syntax/GridifyTypeBuilder.cs | 161 +-
src/Gridify/Syntax/Lexer.cs | 301 ++-
.../Syntax/ParenthesizedExpressionSyntax.cs | 37 +-
src/Gridify/Syntax/Parser.cs | 240 ++-
.../Syntax/ReplaceExpressionVisitor.cs | 29 +-
src/Gridify/Syntax/SyntaxKind.cs | 65 +-
src/Gridify/Syntax/SyntaxNode.cs | 11 +-
src/Gridify/Syntax/SyntaxToken.cs | 37 +-
src/Gridify/Syntax/SyntaxTree.cs | 29 +-
.../Syntax/SyntaxTreeToQueryConvertor.cs | 775 ++++----
src/Gridify/Syntax/ValueExpressionSyntax.cs | 33 +-
.../DatabaseFixture.cs | 53 +-
.../GridifyEntityFrameworkTests.cs | 151 +-
.../MyDbContext.cs | 33 +-
.../GridifyEntityFrameworkSqlTests.cs | 111 +-
.../Interceptors.cs | 205 +-
.../MyDbContext.cs | 37 +-
test/Gridify.Tests/GridifyExtensionsShould.cs | 1735 +++++++++--------
test/Gridify.Tests/GridifyMapperShould.cs | 115 +-
.../GridifyNestedCollectionTests.cs | 497 +++--
test/Gridify.Tests/Issue36Tests.cs | 123 +-
test/Gridify.Tests/QueryBuilderShould.cs | 191 +-
test/Gridify.Tests/TestClass.cs | 59 +-
60 files changed, 4322 insertions(+), 4104 deletions(-)
diff --git a/benchmark/Benchmark.csproj b/benchmark/Benchmark.csproj
index 034107fe..e353df47 100644
--- a/benchmark/Benchmark.csproj
+++ b/benchmark/Benchmark.csproj
@@ -9,6 +9,7 @@
+
diff --git a/benchmark/GridifyMapperUsages.cs b/benchmark/GridifyMapperUsages.cs
index d29d38c6..f276fc5e 100644
--- a/benchmark/GridifyMapperUsages.cs
+++ b/benchmark/GridifyMapperUsages.cs
@@ -7,128 +7,127 @@
using Gridify;
using Gridify.Tests;
-namespace Benchmarks
+namespace Benchmarks;
+
+[MemoryDiagnoser]
+[RPlotExporter]
+[Orderer(SummaryOrderPolicy.FastestToSlowest)]
+public class GridifyMapperUsages
{
- [MemoryDiagnoser]
- [RPlotExporter]
- [Orderer(SummaryOrderPolicy.FastestToSlowest)]
- public class GridifyMapperUsages
- {
- private static readonly Consumer Consumer = new();
- private TestClass[] _data;
- private Func compiled1;
- private Func compiled2;
- private Func compiled3;
+ private static readonly Consumer Consumer = new();
+ private TestClass[] _data;
+ private Func compiled1;
+ private Func compiled2;
+ private Func compiled3;
- private IQueryable Ds => _data.AsQueryable();
- private IEnumerable EnumerableDs => _data.ToList();
- private IGridifyMapper ggm { get; set; }
+ private IQueryable Ds => _data.AsQueryable();
+ private IEnumerable EnumerableDs => _data.ToList();
+ private IGridifyMapper ggm { get; set; }
- [GlobalSetup]
- public void Setup()
- {
- _data = GetSampleData().ToArray();
+ [GlobalSetup]
+ public void Setup()
+ {
+ _data = GetSampleData().ToArray();
- ggm = new GridifyMapper().GenerateMappings();
+ ggm = new GridifyMapper().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();
- }
+ // 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().GenerateMappings();
- Ds.ApplyFiltering("Name=*a", gm).Consume(Consumer);
- Ds.ApplyFiltering("Id>5", gm).Consume(Consumer);
- Ds.ApplyFiltering("Name=Ali", gm).Consume(Consumer);
- }
+ [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().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()
- .AddMap("name")
- .AddMap("id");
+ [Benchmark]
+ public void Gridify_SingleMapper_Manual()
+ {
+ var gm = new GridifyMapper()
+ .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);
- }
+ 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().GenerateMappings()).Consume(Consumer);
- Ds.ApplyFiltering("Id>5", new GridifyMapper().GenerateMappings()).Consume(Consumer);
- Ds.ApplyFiltering("Name=Ali", new GridifyMapper().GenerateMappings()).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().GenerateMappings()).Consume(Consumer);
+ Ds.ApplyFiltering("Id>5", new GridifyMapper().GenerateMappings()).Consume(Consumer);
+ Ds.ApplyFiltering("Name=Ali", new GridifyMapper().GenerateMappings()).Consume(Consumer);
+ }
- // [Benchmark]
- // public void GridifyCompiled()
- // {
- // EnumerableDs.Where(compiled1).Consume(Consumer);
- // EnumerableDs.Where(compiled2).Consume(Consumer);
- // EnumerableDs.Where(compiled3).Consume(Consumer);
- // }
+ // [Benchmark]
+ // public void GridifyCompiled()
+ // {
+ // EnumerableDs.Where(compiled1).Consume(Consumer);
+ // EnumerableDs.Where(compiled2).Consume(Consumer);
+ // EnumerableDs.Where(compiled3).Consume(Consumer);
+ // }
- public static IEnumerable GetSampleData()
- {
- var lst = new List();
- 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;
- }
+ public static IEnumerable GetSampleData()
+ {
+ var lst = new List();
+ 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;
}
}
diff --git a/benchmark/LibraryComparisionFilteringBenchmark.cs b/benchmark/LibraryComparisionFilteringBenchmark.cs
index a861238c..e48b2145 100644
--- a/benchmark/LibraryComparisionFilteringBenchmark.cs
+++ b/benchmark/LibraryComparisionFilteringBenchmark.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
+using System.Linq.Expressions;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using BenchmarkDotNet.Order;
@@ -9,103 +10,128 @@
using Fop.FopExpression;
using Gridify;
using Gridify.Tests;
+using Microsoft.CodeAnalysis.CSharp.Scripting;
+using Microsoft.CodeAnalysis.Scripting;
using Microsoft.Extensions.Options;
using Sieve.Models;
using Sieve.Services;
-namespace Benchmarks
+namespace Benchmarks;
+
+[MemoryDiagnoser]
+[RPlotExporter]
+[Orderer(SummaryOrderPolicy.FastestToSlowest)]
+public class LibraryComparisionFilteringBenchmark
{
- [MemoryDiagnoser]
- [RPlotExporter]
- [Orderer(SummaryOrderPolicy.FastestToSlowest)]
- public class LibraryComparisionFilteringBenchmark
+ private static readonly Consumer Consumer = new();
+ private TestClass[] _data;
+ private ScriptOptions _options;
+ private SieveProcessor _processor;
+ private GridifyMapper _gm;
+
+ private IQueryable Ds => _data.AsQueryable();
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ _data = GetSampleData().ToArray();
+
+ // Sieve
+ _processor = new SieveProcessor(new OptionsWrapper(new SieveOptions()));
+
+ // gridify
+ _gm = new GridifyMapper(true);
+
+ // CSharpScripting
+ _options = ScriptOptions.Default.AddReferences(typeof(TestClass).Assembly);
+ }
+
+
+ [Benchmark(Baseline = true)]
+ public void Native_LINQ()
+ {
+ 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()
+ {
+ Ds.ApplyFiltering("Name=*a", _gm).Consume(Consumer);
+ Ds.ApplyFiltering("Id>5", _gm).Consume(Consumer);
+ Ds.ApplyFiltering("Name=Ali", _gm).Consume(Consumer);
+ }
+
+ [Benchmark]
+ public void Fop()
+ {
+ // fop doesn't have filtering only feature?
+ Ds.ApplyFop(FopExpressionBuilder.Build("Name~=a", "Name", 1, 1000)).Item1.Consume(Consumer);
+ Ds.ApplyFop(FopExpressionBuilder.Build("Id>5", "Name", 1, 1000)).Item1.Consume(Consumer);
+ Ds.ApplyFop(FopExpressionBuilder.Build("Name==Ali", "Name", 1, 1000)).Item1.Consume(Consumer);
+ }
+
+ [Benchmark]
+ public void DynamicLinq()
+ {
+ Ds.Where("Name.Contains(@0)", "a").Consume(Consumer);
+ Ds.Where("Id > (@0)", "5").Consume(Consumer);
+ Ds.Where("Name==(@0)", "Ali").Consume(Consumer);
+ }
+
+ [Benchmark]
+ public void CSharp_Scripting()
+ {
+ // Is there any non-async way to do this?
+ Ds.Where(CSharpScript.EvaluateAsync>>
+ ("q => q.Name.Contains('a')", _options).Result).Consume(Consumer);
+
+ Ds.Where(CSharpScript.EvaluateAsync>>
+ ("q => q.Id > 5", _options).Result).Consume(Consumer);
+
+ Ds.Where(CSharpScript.EvaluateAsync>>
+ ("q => q.Name == \"Ali\"", _options).Result).Consume(Consumer);
+ }
+
+ [Benchmark]
+ public void Sieve()
+ {
+ _processor.Apply(new SieveModel { Filters = "Name@=a" }, Ds, applySorting: false, applyPagination: false).Consume(Consumer);
+ _processor.Apply(new SieveModel { Filters = "Id>5" }, Ds, applySorting: false, applyPagination: false).Consume(Consumer);
+ _processor.Apply(new SieveModel { Filters = "Name==Ali" }, Ds, applySorting: false, applyPagination: false).Consume(Consumer);
+ }
+
+
+ public static IEnumerable GetSampleData()
{
- private static readonly Consumer Consumer = new();
- private TestClass[] _data;
-
- private IQueryable Ds => _data.AsQueryable();
-
- [GlobalSetup]
- public void Setup()
- {
- _data = GetSampleData().ToArray();
- }
-
-
- [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()
- {
- var gm = new GridifyMapper().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 Fop()
- {
- // fop doesn't have filtering only feature
- Ds.ApplyFop(FopExpressionBuilder.Build("Name~=a", "Name", 1, 1000)).Item1.Consume(Consumer);
- Ds.ApplyFop(FopExpressionBuilder.Build("Id>5", "Name", 1, 1000)).Item1.Consume(Consumer);
- Ds.ApplyFop(FopExpressionBuilder.Build("Name==Ali", "Name", 1, 1000)).Item1.Consume(Consumer);
- }
-
- [Benchmark]
- public void DynamicLinQ()
- {
- Ds.Where("Name.Contains(@0)", "a").Consume(Consumer);
- Ds.Where("Id > (@0)", "5").Consume(Consumer);
- Ds.Where("Name==(@0)", "Ali").Consume(Consumer);
- }
-
- [Benchmark]
- public void Sieve()
- {
- var processor = new SieveProcessor(new OptionsWrapper(new SieveOptions()));
- processor.Apply(new SieveModel { Filters = "Name@=a" }, Ds, applySorting: false, applyPagination: false).Consume(Consumer);
- processor.Apply(new SieveModel { Filters = "Id>5" }, Ds, applySorting: false, applyPagination: false).Consume(Consumer);
- processor.Apply(new SieveModel { Filters = "Name==Ali" }, Ds, applySorting: false, applyPagination: false).Consume(Consumer);
- }
-
-
- public static IEnumerable GetSampleData()
- {
- var lst = new List();
- 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;
- }
+ var lst = new List();
+ 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;
}
}
@@ -116,10 +142,11 @@ public static IEnumerable GetSampleData()
// 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 |
+// | Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Allocated |
+// |----------------- |-------------:|------------:|------------:|-------:|--------:|----------:|----------:|----------:|
+// | Native_LINQ | 806.3 us | 4.89 us | 4.57 us | 1.00 | 0.00 | 4.8828 | 1.9531 | 35 KB |
+// | Gridify | 839.6 us | 5.69 us | 4.75 us | 1.04 | 0.01 | 5.8594 | 2.9297 | 39 KB |
+// | DynamicLinq | 973.8 us | 8.65 us | 6.75 us | 1.21 | 0.01 | 19.5313 | 9.7656 | 123 KB |
+// | Sieve | 1,299.7 us | 12.74 us | 11.29 us | 1.61 | 0.02 | 7.8125 | 3.9063 | 53 KB |
+// | Fop | 3,498.6 us | 29.45 us | 26.11 us | 4.34 | 0.03 | 54.6875 | 27.3438 | 348 KB |
+// | CSharp_Scripting | 231,510.6 us | 4,406.95 us | 4,122.26 us | 287.13 | 5.12 | 3000.0000 | 1000.0000 | 24,198 KB |
diff --git a/benchmark/Program.cs b/benchmark/Program.cs
index 3d62ac0a..63793e7e 100644
--- a/benchmark/Program.cs
+++ b/benchmark/Program.cs
@@ -1,17 +1,16 @@
using System;
using BenchmarkDotNet.Running;
-namespace Benchmarks
+namespace Benchmarks;
+
+public class Program
{
- public class Program
+ private static void Main()
{
- private static void Main()
- {
- BenchmarkRunner.Run();
- // BenchmarkRunner.Run();
- // BenchmarkRunner.Run();
- // BenchmarkRunner.Run();
- Console.Read();
- }
+ BenchmarkRunner.Run();
+ // BenchmarkRunner.Run();
+ // BenchmarkRunner.Run();
+ // BenchmarkRunner.Run();
+ Console.Read();
}
-}
+}
\ No newline at end of file
diff --git a/benchmark/QueryBuilderBuildBenchmark.cs b/benchmark/QueryBuilderBuildBenchmark.cs
index c7e46486..20284e22 100644
--- a/benchmark/QueryBuilderBuildBenchmark.cs
+++ b/benchmark/QueryBuilderBuildBenchmark.cs
@@ -7,94 +7,93 @@
using Gridify;
using Gridify.Tests;
-namespace Benchmarks
+namespace Benchmarks;
+
+[MemoryDiagnoser]
+[RPlotExporter]
+[Orderer(SummaryOrderPolicy.FastestToSlowest)]
+public class QueryBuilderBuildBenchmark
{
- [MemoryDiagnoser]
- [RPlotExporter]
- [Orderer(SummaryOrderPolicy.FastestToSlowest)]
- public class QueryBuilderBuildBenchmark
- {
- private readonly IEnumerable _data;
- private static readonly Consumer Consumer = new();
- private readonly Func, IEnumerable> BuildCompiledFuc;
- private readonly Func, IQueryable> BuildFunc;
- private readonly Func BuildFilteringExpressionFunc;
- private readonly Func, Paging> BuildWithPagingCompiledFunc;
- private readonly Func, Paging> BuildWithPagingFunc;
+ private readonly IEnumerable _data;
+ private static readonly Consumer Consumer = new();
+ private readonly Func, IEnumerable> BuildCompiledFuc;
+ private readonly Func, IQueryable> BuildFunc;
+ private readonly Func BuildFilteringExpressionFunc;
+ private readonly Func, Paging> BuildWithPagingCompiledFunc;
+ private readonly Func, Paging> BuildWithPagingFunc;
- public QueryBuilderBuildBenchmark()
- {
- _data = LibraryComparisionFilteringBenchmark.GetSampleData().ToArray();
+ public QueryBuilderBuildBenchmark()
+ {
+ _data = LibraryComparisionFilteringBenchmark.GetSampleData().ToArray();
- var builder = new QueryBuilder()
- .AddCondition("id>2")
- .AddCondition("name=*a");
+ var builder = new QueryBuilder()
+ .AddCondition("id>2")
+ .AddCondition("name=*a");
- BuildCompiledFuc = builder.BuildCompiled();
- BuildFunc = builder.Build();
- BuildFilteringExpressionFunc = builder.BuildFilteringExpression().Compile();
- BuildWithPagingCompiledFunc = builder.BuildWithPagingCompiled();
- BuildWithPagingFunc = builder.BuildWithPaging();
+ BuildCompiledFuc = builder.BuildCompiled();
+ BuildFunc = builder.Build();
+ BuildFilteringExpressionFunc = builder.BuildFilteringExpression().Compile();
+ BuildWithPagingCompiledFunc = builder.BuildWithPagingCompiled();
+ BuildWithPagingFunc = builder.BuildWithPaging();
- TestOutputs();
- }
+ TestOutputs();
+ }
- [Benchmark(Baseline = true)] // this method is only for filtering operations
- public void BuildFilteringExpression()
- {
- _data.Where(BuildFilteringExpressionFunc).Consume(Consumer);
- }
+ [Benchmark(Baseline = true)] // this method is only for filtering operations
+ public void BuildFilteringExpression()
+ {
+ _data.Where(BuildFilteringExpressionFunc).Consume(Consumer);
+ }
- [Benchmark]
- public void Build()
- {
- BuildFunc(_data.AsQueryable()).Consume(Consumer);
- }
+ [Benchmark]
+ public void Build()
+ {
+ BuildFunc(_data.AsQueryable()).Consume(Consumer);
+ }
- [Benchmark]
- public void BuildCompiled()
- {
- BuildCompiledFuc(_data).Consume(Consumer);
- }
+ [Benchmark]
+ public void BuildCompiled()
+ {
+ BuildCompiledFuc(_data).Consume(Consumer);
+ }
- [Benchmark]
- public void BuildWithPaging()
- {
- BuildWithPagingFunc(_data.AsQueryable()).Data.Consume(Consumer);
- }
+ [Benchmark]
+ public void BuildWithPaging()
+ {
+ BuildWithPagingFunc(_data.AsQueryable()).Data.Consume(Consumer);
+ }
- [Benchmark]
- public void BuildWithPagingCompiled()
- {
- BuildWithPagingCompiledFunc(_data.AsQueryable()).Data.Consume(Consumer);
- }
+ [Benchmark]
+ public void BuildWithPagingCompiled()
+ {
+ BuildWithPagingCompiledFunc(_data.AsQueryable()).Data.Consume(Consumer);
+ }
- private void TestOutputs()
+ private void TestOutputs()
+ {
+ if (AllSame(BuildCompiledFuc(_data).Count(), BuildFunc(_data.AsQueryable()).Count(), _data.Where(BuildFilteringExpressionFunc).Count()) &&
+ AllSame(BuildCompiledFuc(_data).First().Id, BuildFunc(_data.AsQueryable()).First().Id,
+ _data.Where(BuildFilteringExpressionFunc).First().Id) &&
+ AllSame(BuildCompiledFuc(_data).Last().Id, BuildFunc(_data.AsQueryable()).Last().Id,
+ _data.Where(BuildFilteringExpressionFunc).Last().Id) &&
+ BuildCompiledFuc(_data).Count() < 2)
{
- if (AllSame(BuildCompiledFuc(_data).Count(), BuildFunc(_data.AsQueryable()).Count(), _data.Where(BuildFilteringExpressionFunc).Count()) &&
- AllSame(BuildCompiledFuc(_data).First().Id, BuildFunc(_data.AsQueryable()).First().Id,
- _data.Where(BuildFilteringExpressionFunc).First().Id) &&
- AllSame(BuildCompiledFuc(_data).Last().Id, BuildFunc(_data.AsQueryable()).Last().Id,
- _data.Where(BuildFilteringExpressionFunc).Last().Id) &&
- BuildCompiledFuc(_data).Count() < 2)
- {
- throw new Exception("MISS MATCH OUTPUT");
- }
+ throw new Exception("MISS MATCH OUTPUT");
}
+ }
- private static bool AllSame(params T[] items)
+ private static bool AllSame(params T[] items)
+ {
+ var first = true;
+ T comparand = default;
+ foreach (var i in items)
{
- var first = true;
- T comparand = default;
- foreach (var i in items)
- {
- if (first) comparand = i;
- else if (!i.Equals(comparand)) return false;
- first = false;
- }
-
- return true;
+ if (first) comparand = i;
+ else if (!i.Equals(comparand)) return false;
+ first = false;
}
+
+ return true;
}
-}
+}
\ No newline at end of file
diff --git a/benchmark/QueryBuilderEvaluatorBenchmark.cs b/benchmark/QueryBuilderEvaluatorBenchmark.cs
index f3a0cbbf..76ee63b1 100644
--- a/benchmark/QueryBuilderEvaluatorBenchmark.cs
+++ b/benchmark/QueryBuilderEvaluatorBenchmark.cs
@@ -7,43 +7,42 @@
using Gridify;
using Gridify.Tests;
-namespace Benchmarks
+namespace Benchmarks;
+
+[MemoryDiagnoser]
+[RPlotExporter]
+[Orderer(SummaryOrderPolicy.FastestToSlowest)]
+public class QueryBuilderEvaluatorBenchmark
{
- [MemoryDiagnoser]
- [RPlotExporter]
- [Orderer(SummaryOrderPolicy.FastestToSlowest)]
- public class QueryBuilderEvaluatorBenchmark
+ private readonly IEnumerable _data;
+ // private static readonly Consumer Consumer = new();
+ private readonly Func,bool> BuildEvaluatorFunc;
+ private readonly Func,bool> BuildCompiledEvaluatorFunc;
+
+ public QueryBuilderEvaluatorBenchmark()
+ {
+ _data = LibraryComparisionFilteringBenchmark.GetSampleData().ToArray();
+
+ var builder = new QueryBuilder()
+ .AddCondition("id>2")
+ .AddCondition("name=*a");
+
+ BuildEvaluatorFunc = builder.BuildEvaluator();
+ BuildCompiledEvaluatorFunc = builder.BuildCompiledEvaluator();
+ }
+
+ [Benchmark]
+ public void BuildEvaluator()
{
- private readonly IEnumerable _data;
- // private static readonly Consumer Consumer = new();
- private readonly Func,bool> BuildEvaluatorFunc;
- private readonly Func,bool> BuildCompiledEvaluatorFunc;
-
- public QueryBuilderEvaluatorBenchmark()
- {
- _data = LibraryComparisionFilteringBenchmark.GetSampleData().ToArray();
-
- var builder = new QueryBuilder()
- .AddCondition("id>2")
- .AddCondition("name=*a");
-
- BuildEvaluatorFunc = builder.BuildEvaluator();
- BuildCompiledEvaluatorFunc = builder.BuildCompiledEvaluator();
- }
-
- [Benchmark]
- public void BuildEvaluator()
- {
- BuildEvaluatorFunc(_data.AsQueryable());
- }
-
- [Benchmark]
- public void BuildCompiledEvaluator()
- {
- BuildCompiledEvaluatorFunc(_data);
- }
+ BuildEvaluatorFunc(_data.AsQueryable());
+ }
+ [Benchmark]
+ public void BuildCompiledEvaluator()
+ {
+ BuildCompiledEvaluatorFunc(_data);
}
+
}
/* Last Run:
diff --git a/benchmark/TestClass.cs b/benchmark/TestClass.cs
index e6a64406..7f05827e 100644
--- a/benchmark/TestClass.cs
+++ b/benchmark/TestClass.cs
@@ -1,40 +1,39 @@
using System;
using Sieve.Attributes;
-namespace Gridify.Tests
+namespace Gridify.Tests;
+
+public class TestClass : ICloneable
{
- public class TestClass : ICloneable
+ public TestClass()
{
- public TestClass()
- {
- }
+ }
- public TestClass(int id, string name, TestClass classProp, Guid myGuid = default, DateTime? date = default)
- {
- Id = id;
- Name = name;
- ChildClass = classProp;
- MyGuid = myGuid;
- MyDateTime = date;
- }
- [Sieve(CanFilter = true, CanSort = true)]
- public int Id { get; set; }
- [Sieve(CanFilter = true, CanSort = true)]
- public string Name { get; set; }
- public TestClass ChildClass { get; set; }
- public DateTime? MyDateTime { get; set; }
- public Guid MyGuid { get; set; }
+ public TestClass(int id, string name, TestClass classProp, Guid myGuid = default, DateTime? date = default)
+ {
+ Id = id;
+ Name = name;
+ ChildClass = classProp;
+ MyGuid = myGuid;
+ MyDateTime = date;
+ }
+ [Sieve(CanFilter = true, CanSort = true)]
+ public int Id { get; set; }
+ [Sieve(CanFilter = true, CanSort = true)]
+ public string Name { get; set; }
+ public TestClass ChildClass { get; set; }
+ public DateTime? MyDateTime { get; set; }
+ public Guid MyGuid { get; set; }
- public object Clone()
+ public object Clone()
+ {
+ return new TestClass
{
- return new TestClass
- {
- Id = Id,
- Name = Name,
- ChildClass = ChildClass != null ? (TestClass) ChildClass.Clone() : null,
- MyGuid = MyGuid
- };
- }
+ Id = Id,
+ Name = Name,
+ ChildClass = ChildClass != null ? (TestClass) ChildClass.Clone() : null,
+ MyGuid = MyGuid
+ };
}
}
\ No newline at end of file
diff --git a/docs/contribution/README.md b/docs/contribution/README.md
index 97d01106..a9d5fe97 100644
--- a/docs/contribution/README.md
+++ b/docs/contribution/README.md
@@ -6,11 +6,10 @@ start contributing to the project by submitting pull requests
## Todos
-- :zap: Improve the documentation site
-- :zap: Improve code documentation (summary)
-- :zap: Add project Security Policy
-- :zap: Validation method [#48](https://github.com/alirezanet/Gridify/issues/48)
-- :zap: Add Support EF.Function.FreeText [#42](https://github.com/alirezanet/Gridify/issues/42)
+- :zap: Improve the documentation site
+- :zap: Improve code documentation (summary)
+- :zap: Add project Security Policy
+- :zap: Add Support EF.Function.FreeText [#42](https://github.com/alirezanet/Gridify/issues/42)
## Documentation
@@ -44,6 +43,6 @@ check out the [github contributing guide](https://git-scm.com/book/en/v2/GitHub-
## Contributors
-- [AliReZa Sabouri](https://github.com/alirezanet)
-- [Alireza Arabshahi](https://github.com/AlirezaArabshahi)
-- Add your name
+- [AliReZa Sabouri](https://github.com/alirezanet)
+- [Alireza Arabshahi](https://github.com/AlirezaArabshahi)
+- Add your name
diff --git a/docs/guide/README.md b/docs/guide/README.md
index 328c625b..19947e1a 100644
--- a/docs/guide/README.md
+++ b/docs/guide/README.md
@@ -17,18 +17,31 @@ 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 | 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 |
+| Method | Mean | Error | Ratio | Gen 0 | Gen 1 | Allocated |
+|------------------|-------------:|------------:|-------:|----------:|----------:|----------:|
+| Native LINQ | 806.3 us | 4.89 us | 1.00 | 4.8828 | 1.9531 | 35 KB |
+| Gridify | 839.6 us | 5.69 us | 1.04 | 5.8594 | 2.9297 | 39 KB |
+| DynamicLinq | 973.8 us | 8.65 us | 1.21 | 19.5313 | 9.7656 | 123 KB |
+| Sieve | 1,299.7 us | 12.74 us | 1.61 | 7.8125 | 3.9063 | 53 KB |
+| Fop | 3,498.6 us | 29.45 us | 4.34 | 54.6875 | 27.3438 | 348 KB |
+| CSharp Scripting | 231,510.6 us | 4,406.95 us | 287.13 | 3000.0000 | 1000.0000 | 24,198 KB |
+
::: details
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
+[Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
+DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
+
+This Benchmark is available [Here](https://github.com/alirezanet/Gridify/blob/master/benchmark/LibraryComparisionFilteringBenchmark.cs)
:::
+
+
+
+
+
diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md
index 81b75f82..50826406 100644
--- a/docs/guide/getting-started.md
+++ b/docs/guide/getting-started.md
@@ -1,3 +1,4 @@
+
# Getting Started
There are two packages available for gridify in the nuget repository.
diff --git a/docs/guide/gridifyQuery.md b/docs/guide/gridifyQuery.md
index 02a686bf..4575ad33 100644
--- a/docs/guide/gridifyQuery.md
+++ b/docs/guide/gridifyQuery.md
@@ -1,4 +1,5 @@
# GridifyQuery
+
GridifyQuery is a simple class for configuring Filtering, Ordering and Paging.
``` csharp
@@ -14,7 +15,41 @@ var gq = new GridifyQuery()
Paging result = personsRepo.Gridify(gq);
```
+## IsValid
+
+This extension method, checks if the GridifyQuery (Filter, OrderBy) is valid to use with a custom mapper or the auto generated mapper and returns true or false.
+
+``` csharp
+var gq = new GridifyQuery() { Filter = "name=John" , OrderBy = "Age" };
+// true
+bool isValid = gq.IsValid();
+```
+
+``` csharp
+var gq = new GridifyQuery() { Filter = "NonExist=John" , OrderBy = "Age" };
+// false (NonExist is not a property of Person)
+bool isValid = gq.IsValid();
+```
+
+``` csharp
+var gq = new GridifyQuery() { Filter = "@name=!" , OrderBy = "Age" };
+// false (this is not a valid filter)
+bool isValid = gq.IsValid();
+```
+
+Optionally you can pass a custom mapper to check if the GridifyQuery is valid for that mapper.
+
+``` csharp
+var mapper = new GridifyMapper()
+ .AddMap("name", q => q.Name);
+var gq = new GridifyQuery() { Filter = "name=John" , OrderBy = "Age" };
+
+// false (Age is not mapped)
+bool isValid = gq.IsValid(mapper);
+```
+
## GetFilteringExpression
+
This extension method, creates a lambda expression using the `GridifyQuery.Filter` property that you can use it in the LINQ `Where` method to filter the data.
``` csharp{2}
@@ -22,3 +57,5 @@ var gq = new GridifyQuery() { Filter = "name=John" };
Expression> expression = gq.GetFilteringExpression();
var result = personsRepo.Where(expression);
```
+
+
diff --git a/docs/guide/queryBuilder.md b/docs/guide/queryBuilder.md
index 64396ca9..9f33b2b8 100644
--- a/docs/guide/queryBuilder.md
+++ b/docs/guide/queryBuilder.md
@@ -13,6 +13,7 @@ The QueryBuilder class is really useful if you want to manually build your query
| AddMap | Add a single Map to existing mapper |
| RemoveMap | Remove a single Map from existing mapper |
| ConfigureDefaultMapper | Configuring default mapper when we didn't use AddMapper method |
+| IsValid | Validates Condition, OrderBy, Query , Mapper and returns a bool |
| Build | Applies filtering ordering and paging to a queryable context |
| BuildCompiled | Compiles the expressions and returns a delegate for applying filtering ordering and paging to a enumerable collection |
| BuildFilteringExpression | Returns filtering expression that can be compiled for later use for enumerable collections |
diff --git a/src/Gridify.EntityFramework/Gridify.EntityFramework.csproj b/src/Gridify.EntityFramework/Gridify.EntityFramework.csproj
index 4dcfe053..0c289386 100644
--- a/src/Gridify.EntityFramework/Gridify.EntityFramework.csproj
+++ b/src/Gridify.EntityFramework/Gridify.EntityFramework.csproj
@@ -2,7 +2,7 @@
netstandard2.0
Gridify.EntityFramework
- 2.4.6
+ 2.4.7
Alireza Sabouri
TuxTeam
Gridify (EntityFramework), Easy and optimized way to apply Filtering, Sorting, and Pagination using text-based data.
diff --git a/src/Gridify/GMap.cs b/src/Gridify/GMap.cs
index 13e9b538..ebd3ad83 100644
--- a/src/Gridify/GMap.cs
+++ b/src/Gridify/GMap.cs
@@ -2,28 +2,27 @@
using System.Linq.Expressions;
using System.Text.RegularExpressions;
-namespace Gridify
+namespace Gridify;
+
+public class GMap : IGMap
{
- public class GMap : IGMap
- {
- public string From { get; set; }
- public LambdaExpression To { get; set; }
- public Func? Convertor { get; set; }
+ public string From { get; set; }
+ public LambdaExpression To { get; set; }
+ public Func? Convertor { get; set; }
- public GMap(string from, Expression> to, Func? convertor = null)
- {
- From = from;
- To = to;
- Convertor = convertor;
- }
+ public GMap(string from, Expression> to, Func? convertor = null)
+ {
+ From = from;
+ To = to;
+ Convertor = convertor;
+ }
- internal bool IsNestedCollection() => Regex.IsMatch(To.ToString(), @"\.Select\s*\(");
+ internal bool IsNestedCollection() => Regex.IsMatch(To.ToString(), @"\.Select\s*\(");
- public GMap(string from, Expression> to, Func? convertor = null)
- {
- From = from;
- To = to;
- Convertor = convertor;
- }
+ public GMap(string from, Expression> to, Func? convertor = null)
+ {
+ From = from;
+ To = to;
+ Convertor = convertor;
}
-}
+}
\ No newline at end of file
diff --git a/src/Gridify/Gridify.csproj b/src/Gridify/Gridify.csproj
index e3eabebc..1df5711a 100644
--- a/src/Gridify/Gridify.csproj
+++ b/src/Gridify/Gridify.csproj
@@ -3,7 +3,7 @@
netstandard2.0
Gridify
- 2.4.6
+ 2.4.7
Alireza Sabouri
TuxTeam
Gridify, Easy and optimized way to apply Filtering, Sorting, and Pagination using text-based data.
diff --git a/src/Gridify/GridifyExtensions.cs b/src/Gridify/GridifyExtensions.cs
index b9ae386f..054ba288 100644
--- a/src/Gridify/GridifyExtensions.cs
+++ b/src/Gridify/GridifyExtensions.cs
@@ -7,507 +7,570 @@
[assembly: InternalsVisibleTo("Gridify.EntityFramework")]
-namespace Gridify
-{
- public static partial class GridifyExtensions
- {
- internal static bool EntityFrameworkCompatibilityLayer { get; set; }
- public static int DefaultPageSize { get; set; } = 20;
-
- #region "Private"
+namespace Gridify;
- ///
- /// Set default Page number and PageSize if its not already set in gridifyQuery
- ///
- /// query and paging configuration
- /// returns a IGridifyPagination with valid PageSize and Page
- private static IGridifyPagination FixPagingData(this IGridifyPagination gridifyPagination)
- {
- // set default for page number
- if (gridifyPagination.Page <= 0)
- gridifyPagination.Page = 1;
-
- // set default for PageSize
- if (gridifyPagination.PageSize <= 0)
- gridifyPagination.PageSize = DefaultPageSize;
+public static partial class GridifyExtensions
+{
+ internal static bool EntityFrameworkCompatibilityLayer { get; set; }
+ public static int DefaultPageSize { get; set; } = 20;
- return gridifyPagination;
- }
+ #region "Private"
- #endregion
+ ///
+ /// Set default Page number and PageSize if its not already set in gridifyQuery
+ ///
+ /// query and paging configuration
+ /// returns a IGridifyPagination with valid PageSize and Page
+ private static IGridifyPagination FixPagingData(this IGridifyPagination gridifyPagination)
+ {
+ // set default for page number
+ if (gridifyPagination.Page <= 0)
+ gridifyPagination.Page = 1;
- public static Expression> GetFilteringExpression(this IGridifyFiltering gridifyFiltering, IGridifyMapper? mapper = null)
- {
- if (string.IsNullOrWhiteSpace(gridifyFiltering.Filter))
- throw new GridifyQueryException("Filter is not defined");
+ // set default for PageSize
+ if (gridifyPagination.PageSize <= 0)
+ gridifyPagination.PageSize = DefaultPageSize;
- var syntaxTree = SyntaxTree.Parse(gridifyFiltering.Filter!);
+ return gridifyPagination;
+ }
- if (syntaxTree.Diagnostics.Any())
- throw new GridifyFilteringException(syntaxTree.Diagnostics.Last()!);
+ #endregion
- mapper = mapper.FixMapper(syntaxTree);
- var (queryExpression, _) = ExpressionToQueryConvertor.GenerateQuery(syntaxTree.Root, mapper);
- if (queryExpression == null) throw new GridifyQueryException("Can not create expression with current data");
- return queryExpression;
- }
+ public static Expression> GetFilteringExpression(this IGridifyFiltering gridifyFiltering, IGridifyMapper? mapper = null)
+ {
+ if (string.IsNullOrWhiteSpace(gridifyFiltering.Filter))
+ throw new GridifyQueryException("Filter is not defined");
- public static IEnumerable>> GetOrderingExpressions(this IGridifyOrdering gridifyOrdering,
- IGridifyMapper? mapper = null)
- {
- if (string.IsNullOrWhiteSpace(gridifyOrdering.OrderBy))
- throw new GridifyQueryException("OrderBy is not defined or not Found");
+ var syntaxTree = SyntaxTree.Parse(gridifyFiltering.Filter!);
+ if (syntaxTree.Diagnostics.Any())
+ throw new GridifyFilteringException(syntaxTree.Diagnostics.Last()!);
- var members = ParseOrderings(gridifyOrdering.OrderBy!).Select(q => q.memberName).ToList();
- if (mapper is null)
- {
- foreach (var member in members)
- {
- Expression>? exp = null;
- try
- {
- exp = GridifyMapper.CreateExpression(member);
- }
- catch (Exception)
- {
- // skip if there is no mappings available
- }
-
- if (exp != null) yield return exp;
- }
- }
- else
- {
- foreach (var member in members.Where(mapper.HasMap))
- {
- yield return mapper.GetExpression(member)!;
- }
- }
- }
+ mapper = mapper.FixMapper(syntaxTree);
+ var (queryExpression, _) = ExpressionToQueryConvertor.GenerateQuery(syntaxTree.Root, mapper);
+ if (queryExpression == null) throw new GridifyQueryException("Can not create expression with current data");
+ return queryExpression;
+ }
- #region "Public"
+ public static IEnumerable>> GetOrderingExpressions(this IGridifyOrdering gridifyOrdering,
+ IGridifyMapper? mapper = null)
+ {
+ if (string.IsNullOrWhiteSpace(gridifyOrdering.OrderBy))
+ throw new GridifyQueryException("OrderBy is not defined or not Found");
- ///
- /// create and return a default GridifyMapper
- ///
- /// type to set mappings
- /// returns an auto generated GridifyMapper
- private static IGridifyMapper GetDefaultMapper()
- {
- return new GridifyMapper().GenerateMappings();
- }
- ///
- /// if given mapper was null this function creates default generated mapper
- ///
- /// a GridifyMapper that can be null
- /// optional syntaxTree to Lazy mapping generation
- /// type to set mappings
- /// return back mapper or new generated mapper if it was null
- private static IGridifyMapper FixMapper(this IGridifyMapper? mapper, SyntaxTree syntaxTree)
+ var members = ParseOrderings(gridifyOrdering.OrderBy!).Select(q => q.memberName).ToList();
+ if (mapper is null)
{
- if (mapper != null) return mapper;
-
- mapper = new GridifyMapper();
- foreach (var field in syntaxTree.Root.Descendants()
- .Where(q => q.Kind == SyntaxKind.FieldExpression)
- .Cast())
+ foreach (var member in members)
{
+ Expression>? exp = null;
try
{
- mapper.AddMap(field.FieldToken.Text);
+ exp = GridifyMapper.CreateExpression(member);
}
catch (Exception)
{
- if (!mapper.Configuration.IgnoreNotMappedFields)
- throw new GridifyMapperException($"Property '{field.FieldToken.Text}' not found.");
+ // skip if there is no mappings available
}
- }
- return mapper;
+ if (exp != null) yield return exp;
+ }
}
-
- private static IEnumerable Descendants(this SyntaxNode root)
+ else
{
- var nodes = new Stack(new[] { root });
- while (nodes.Any())
+ foreach (var member in members.Where(mapper.HasMap))
{
- SyntaxNode node = nodes.Pop();
- yield return node;
- foreach (var n in node.GetChildren()) nodes.Push(n);
+ yield return mapper.GetExpression(member)!;
}
}
+ }
- ///
- /// adds Filtering,Ordering And Paging to the query
- ///
- /// the original(target) queryable object
- /// the configuration to apply paging, filtering and ordering
- /// this is an optional parameter to apply filtering and ordering using a custom mapping configuration
- /// type of target entity
- /// returns user query after applying filtering, ordering and paging
- public static IQueryable ApplyFilteringOrderingPaging(this IQueryable query, IGridifyQuery? gridifyQuery,
- IGridifyMapper? mapper = null)
- {
- if (gridifyQuery == null) return query;
+ #region "Public"
- query = query.ApplyFiltering(gridifyQuery, mapper);
- query = query.ApplyOrdering(gridifyQuery, mapper);
- query = query.ApplyPaging(gridifyQuery);
- return query;
- }
+ ///
+ /// create and return a default GridifyMapper
+ ///
+ /// type to set mappings
+ /// returns an auto generated GridifyMapper
+ private static IGridifyMapper GetDefaultMapper()
+ {
+ return new GridifyMapper().GenerateMappings();
+ }
+
+ ///
+ /// if given mapper was null this function creates default generated mapper
+ ///
+ /// a GridifyMapper that can be null
+ /// optional syntaxTree to Lazy mapping generation
+ /// type to set mappings
+ /// return back mapper or new generated mapper if it was null
+ private static IGridifyMapper FixMapper(this IGridifyMapper? mapper, SyntaxTree syntaxTree)
+ {
+ if (mapper != null) return mapper;
- ///
- /// adds Ordering to the query
- ///
- /// the original(target) queryable object
- /// the configuration to apply ordering
- /// this is an optional parameter to apply ordering using a custom mapping configuration
- /// if you already have an ordering with start with ThenBy, new orderings will add on top of your orders
- /// type of target entity
- /// returns user query after applying Ordering
- public static IQueryable ApplyOrdering(this IQueryable query, IGridifyOrdering? gridifyOrdering, IGridifyMapper? mapper = null,
- bool startWithThenBy = false)
+ mapper = new GridifyMapper();
+ foreach (var field in syntaxTree.Root.Descendants()
+ .Where(q => q.Kind == SyntaxKind.FieldExpression)
+ .Cast())
{
- if (gridifyOrdering == null) return query;
- return string.IsNullOrWhiteSpace(gridifyOrdering.OrderBy)
- ? query
- : ProcessOrdering(query, gridifyOrdering.OrderBy!, startWithThenBy, mapper);
+ try
+ {
+ mapper.AddMap(field.FieldToken.Text);
+ }
+ catch (Exception)
+ {
+ if (!mapper.Configuration.IgnoreNotMappedFields)
+ throw new GridifyMapperException($"Property '{field.FieldToken.Text}' not found.");
+ }
}
- ///
- /// adds Ordering to the query
- ///
- /// the original(target) queryable object
- /// the ordering fields
- /// this is an optional parameter to apply ordering using a custom mapping configuration
- /// if you already have an ordering with start with ThenBy, new orderings will add on top of your orders
- /// type of target entity
- /// returns user query after applying Ordering
- public static IQueryable ApplyOrdering(this IQueryable query, string orderBy, IGridifyMapper? mapper = null,
- bool startWithThenBy = false)
+ return mapper;
+ }
+
+ private static IEnumerable Descendants(this SyntaxNode root)
+ {
+ var nodes = new Stack(new[] { root });
+ while (nodes.Any())
{
- return string.IsNullOrWhiteSpace(orderBy)
- ? query
- : ProcessOrdering(query, orderBy, startWithThenBy, mapper);
+ SyntaxNode node = nodes.Pop();
+ yield return node;
+ foreach (var n in node.GetChildren()) nodes.Push(n);
}
+ }
+
+ ///
+ /// adds Filtering,Ordering And Paging to the query
+ ///
+ /// the original(target) queryable object
+ /// the configuration to apply paging, filtering and ordering
+ /// this is an optional parameter to apply filtering and ordering using a custom mapping configuration
+ /// type of target entity
+ /// returns user query after applying filtering, ordering and paging
+ public static IQueryable ApplyFilteringOrderingPaging(this IQueryable query, IGridifyQuery? gridifyQuery,
+ IGridifyMapper? mapper = null)
+ {
+ if (gridifyQuery == null) return query;
+
+ query = query.ApplyFiltering(gridifyQuery, mapper);
+ query = query.ApplyOrdering(gridifyQuery, mapper);
+ query = query.ApplyPaging(gridifyQuery);
+ return query;
+ }
+
+ ///
+ /// adds Ordering to the query
+ ///
+ /// the original(target) queryable object
+ /// the configuration to apply ordering
+ /// this is an optional parameter to apply ordering using a custom mapping configuration
+ /// if you already have an ordering with start with ThenBy, new orderings will add on top of your orders
+ /// type of target entity
+ /// returns user query after applying Ordering
+ public static IQueryable ApplyOrdering(this IQueryable query, IGridifyOrdering? gridifyOrdering, IGridifyMapper? mapper = null,
+ bool startWithThenBy = false)
+ {
+ if (gridifyOrdering == null) return query;
+ return string.IsNullOrWhiteSpace(gridifyOrdering.OrderBy)
+ ? query
+ : ProcessOrdering(query, gridifyOrdering.OrderBy!, startWithThenBy, mapper);
+ }
+
+ ///
+ /// adds Ordering to the query
+ ///
+ /// the original(target) queryable object
+ /// the ordering fields
+ /// this is an optional parameter to apply ordering using a custom mapping configuration
+ /// if you already have an ordering with start with ThenBy, new orderings will add on top of your orders
+ /// type of target entity
+ /// returns user query after applying Ordering
+ public static IQueryable ApplyOrdering(this IQueryable query, string orderBy, IGridifyMapper? mapper = null,
+ bool startWithThenBy = false)
+ {
+ return string.IsNullOrWhiteSpace(orderBy)
+ ? query
+ : ProcessOrdering(query, orderBy, startWithThenBy, mapper);
+ }
+
+ public static IQueryable