From d6611d8979bcb8e2f2af8878d72155de1ad9a7cc Mon Sep 17 00:00:00 2001 From: Seniister Date: Wed, 13 Jul 2022 17:04:37 +0300 Subject: [PATCH 01/10] Added Examples sections --- PlayGround/appsettings.json | 2 +- ShiftGrid.Core/docs/examples.md | 39 ++++++ ShiftGrid.Core/docs/methods.md | 38 ++++++ ShiftGrid.Core/mkdocs.yml | 1 + ShiftGrid.postman_collection.json | 193 ++++++++++++++++++++++++++++++ 5 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 ShiftGrid.Core/docs/examples.md create mode 100644 ShiftGrid.postman_collection.json diff --git a/PlayGround/appsettings.json b/PlayGround/appsettings.json index 6c7510a..563ec09 100644 --- a/PlayGround/appsettings.json +++ b/PlayGround/appsettings.json @@ -8,7 +8,7 @@ "AllowedHosts": "*", "Settings": { "ConnectionStrings": { - "SqlServer": "Data Source=localhost\\sqlexpress;Initial Catalog=ShiftGrid_PlayGround;User Id=sa; Password=1234554321; MultipleActiveResultSets=True" + "SqlServer": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=ShiftGrid_PlayGround;MultipleActiveResultSets=True" } } } diff --git a/ShiftGrid.Core/docs/examples.md b/ShiftGrid.Core/docs/examples.md new file mode 100644 index 0000000..0e2c34b --- /dev/null +++ b/ShiftGrid.Core/docs/examples.md @@ -0,0 +1,39 @@ +### Filtering +There are many ways of filtering. Here are some examples of it. +#### Starts With +`StartsWith` can be used to filter the data depending of what value the data begins with. +``` C# +[HttpPost("filters")] + public async Task Filters() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = nameof(Employee.FirstName), + Operator = GridFilterOperator.StartsWith, + Value = "First Name (1" + } + } + }); + + //It's better to use nameof. When targetting fields in Filters and Columns. + return Ok(shiftGrid); + } +``` diff --git a/ShiftGrid.Core/docs/methods.md b/ShiftGrid.Core/docs/methods.md index 4ed3643..ef33fa4 100644 --- a/ShiftGrid.Core/docs/methods.md +++ b/ShiftGrid.Core/docs/methods.md @@ -17,6 +17,44 @@ Parameters: | `stableSortDirection` | [`SortDirection`](/reference/#gridsort)
The sort direction for the Stable Sorting.
Defaults to `Ascending` | | `gridConfig` | [`GridConfig`](/reference/#gridconfig)
This is how the grid is controlled. Page Size, Page Index, Filters, Sorting ...etc | +#### GridConfig | GridFilter +GridConfig accepts a list of [`GridFilter`](/reference/#gridfilter) where you can specify 4 paramters for each [`GridFilter`](/reference/#gridfilter) item which are `Field`, `Operator`, `Value` and `Or`. +``` C# +[HttpPost("filters")] + public async Task Filters() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = nameof(Employee.FirstName), + Operator = GridFilterOperator.StartsWith, + Value = "First Name (1" + } + } + }); + + //It's better to use nameof. When targetting fields in Filters and Columns. + return Ok(shiftGrid); + } +``` + ### SelectAggregate Used for Aggregating data. diff --git a/ShiftGrid.Core/mkdocs.yml b/ShiftGrid.Core/mkdocs.yml index 96d8422..7f57db3 100644 --- a/ShiftGrid.Core/mkdocs.yml +++ b/ShiftGrid.Core/mkdocs.yml @@ -20,6 +20,7 @@ nav: - Getting Started: 'getting-started.md' - Reference: 'reference.md' - Methods: 'methods.md' + - Examples: 'examples.md' extra_css: - overrides/css/extra.css extra: diff --git a/ShiftGrid.postman_collection.json b/ShiftGrid.postman_collection.json new file mode 100644 index 0000000..55c58cb --- /dev/null +++ b/ShiftGrid.postman_collection.json @@ -0,0 +1,193 @@ +{ + "info": { + "_postman_id": "f1642c49-18d4-4dd0-9ad9-65a40148c5cd", + "name": "ShiftGrid", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "5139868" + }, + "item": [ + { + "name": "Basic", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"dataPageIndex\": 0,\r\n \"dataPageSize\": 5,\r\n \"sort\": [\r\n {\r\n \"field\": \"ID\",\r\n \"sortDirection\": 0\r\n }\r\n ],\r\n \"columns\": [],\r\n \"pagination\": {\r\n \"pageSize\": 10\r\n },\r\n \"filters\": [\r\n \r\n ]\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ShiftGridHost}}/api/basic", + "host": [ + "{{ShiftGridHost}}" + ], + "path": [ + "api", + "basic" + ] + } + }, + "response": [] + }, + { + "name": "Aggregate", + "request": { + "method": "POST", + "header": [ + { + "key": "database", + "value": "SqlServer", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"dataPageIndex\": 0,\r\n \"dataPageSize\": 5,\r\n \"sort\": [\r\n {\r\n \"field\": \"ID\",\r\n \"sortDirection\": 0\r\n }\r\n ],\r\n \"columns\": [],\r\n \"pagination\": {\r\n \"pageSize\": 10\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ShiftGridHost}}/api/aggregate", + "host": [ + "{{ShiftGridHost}}" + ], + "path": [ + "api", + "aggregate" + ] + } + }, + "response": [] + }, + { + "name": "Columns", + "request": { + "method": "POST", + "header": [ + { + "key": "database", + "value": "SqlServer", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"dataPageIndex\": 0,\r\n \"dataPageSize\": 5,\r\n \"sort\": [\r\n {\r\n \"field\": \"ID\",\r\n \"sortDirection\": 0\r\n }\r\n ],\r\n \"columns\": [],\r\n \"pagination\": {\r\n \"pageSize\": 10\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ShiftGridHost}}/api/columns", + "host": [ + "{{ShiftGridHost}}" + ], + "path": [ + "api", + "columns" + ] + } + }, + "response": [] + }, + { + "name": "Filters", + "request": { + "method": "POST", + "header": [ + { + "key": "database", + "value": "SqlServer", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"dataPageIndex\": 0,\r\n \"dataPageSize\": 5,\r\n \"sort\": [\r\n {\r\n \"field\": \"ID\",\r\n \"sortDirection\": 0\r\n }\r\n ],\r\n \"columns\": [],\r\n \"pagination\": {\r\n \"pageSize\": 10\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ShiftGridHost}}/api/filters", + "host": [ + "{{ShiftGridHost}}" + ], + "path": [ + "api", + "filters" + ] + } + }, + "response": [] + }, + { + "name": "No Config", + "request": { + "method": "POST", + "header": [ + { + "key": "database", + "value": "SqlServer", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"dataPageIndex\": 0,\r\n \"dataPageSize\": 5,\r\n \"sort\": [\r\n {\r\n \"field\": \"ID\",\r\n \"sortDirection\": 0\r\n }\r\n ],\r\n \"columns\": [],\r\n \"pagination\": {\r\n \"pageSize\": 10\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ShiftGridHost}}/api/no-config", + "host": [ + "{{ShiftGridHost}}" + ], + "path": [ + "api", + "no-config" + ] + } + }, + "response": [] + }, + { + "name": "Insert Test Data", + "request": { + "method": "POST", + "header": [ + { + "key": "database", + "value": "SqlServer", + "type": "text" + } + ], + "url": { + "raw": "{{ShiftGridHost}}/api/insert-test-data", + "host": [ + "{{ShiftGridHost}}" + ], + "path": [ + "api", + "insert-test-data" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file From 5e48516587819545fb2ed13403540daa8bce7d48 Mon Sep 17 00:00:00 2001 From: Seniister Date: Wed, 13 Jul 2022 17:10:07 +0300 Subject: [PATCH 02/10] Added Examples sections --- ShiftGrid.Core/mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/ShiftGrid.Core/mkdocs.yml b/ShiftGrid.Core/mkdocs.yml index 96d8422..bd072eb 100644 --- a/ShiftGrid.Core/mkdocs.yml +++ b/ShiftGrid.Core/mkdocs.yml @@ -20,6 +20,7 @@ nav: - Getting Started: 'getting-started.md' - Reference: 'reference.md' - Methods: 'methods.md' + - Examples: "examples.md" extra_css: - overrides/css/extra.css extra: From d399a25db1d25d98c6b8d55957b4f4ca324883bd Mon Sep 17 00:00:00 2001 From: Seniister Date: Sun, 17 Jul 2022 11:13:08 +0300 Subject: [PATCH 03/10] Added Examples --- PlayGround/Controllers/Default.cs | 66 +++++++++++++++++++++ ShiftGrid.Core/docs/examples.md | 98 +++++++++++++++++++++++++++++++ ShiftGrid.Core/mkdocs.yml | 1 + 3 files changed, 165 insertions(+) diff --git a/PlayGround/Controllers/Default.cs b/PlayGround/Controllers/Default.cs index accd4f9..d25c17e 100644 --- a/PlayGround/Controllers/Default.cs +++ b/PlayGround/Controllers/Default.cs @@ -174,6 +174,72 @@ await db //It's better to use nameof. When targetting fields in Filters and Columns. return Ok(shiftGrid); } + [HttpPost("filters_equals")] + public async Task Filters_Equals() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = 1 + } + } + }); + + //It's better to use nameof. When targetting fields in Filters and Columns. + return Ok(shiftGrid); + } + [HttpPost("filters_in")] + public async Task Filters_In() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = nameof(Employee.ID), + Operator = GridFilterOperator.In, + Value = new List { 1, 4, 10 } + } + } + }); + + //It's better to use nameof. When targetting fields in Filters and Columns. + return Ok(shiftGrid); + } [FileHelpers.DelimitedRecord(",")] public class EmployeeCSV diff --git a/ShiftGrid.Core/docs/examples.md b/ShiftGrid.Core/docs/examples.md index 0e2c34b..c24ea01 100644 --- a/ShiftGrid.Core/docs/examples.md +++ b/ShiftGrid.Core/docs/examples.md @@ -1,5 +1,95 @@ ### Filtering There are many ways of filtering. Here are some examples of it. +#### Equals +`Equals` can be used to get only one record with the given specification. +``` C# +[HttpPost("filters")] + public async Task Filters() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = 1 + } + } + }); + + //It's better to use nameof. When targetting fields in Filters and Columns. + return Ok(shiftGrid); + } +``` +The above example (when using EF Core and SQL Server) generates an SQL like below +``` SQL +SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[Name] AS [Department] +FROM [Employees] AS [e] +LEFT JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[ID] +WHERE [e].[ID] = CAST(1 AS bigint) +ORDER BY [e].[ID] +``` +#### In +`In` can be used to get multiple records with the given specification. +``` C# +[HttpPost("filters")] + public async Task Filters() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = nameof(Employee.ID), + Operator = GridFilterOperator.In, + Value = new List { 1, 4, 10 } + } + } + }); + + //It's better to use nameof. When targetting fields in Filters and Columns. + return Ok(shiftGrid); + } +``` +The above example (when using EF Core and SQL Server) generates an SQL like below +``` SQL +SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[Name] AS [Department] +FROM [Employees] AS [e] +LEFT JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[ID] +WHERE [e].[ID] IN (CAST(1 AS bigint), CAST(4 AS bigint), CAST(10 AS bigint)) +ORDER BY [e].[ID] +``` #### Starts With `StartsWith` can be used to filter the data depending of what value the data begins with. ``` C# @@ -37,3 +127,11 @@ There are many ways of filtering. Here are some examples of it. return Ok(shiftGrid); } ``` +The above example (when using EF Core and SQL Server) generates an SQL like below +``` SQL +SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[Name] AS [Department] +FROM [Employees] AS [e] +LEFT JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[ID] +WHERE [e].[FirstName] LIKE N'First Name (1%' +ORDER BY [e].[ID] +``` diff --git a/ShiftGrid.Core/mkdocs.yml b/ShiftGrid.Core/mkdocs.yml index bd072eb..03f7e8c 100644 --- a/ShiftGrid.Core/mkdocs.yml +++ b/ShiftGrid.Core/mkdocs.yml @@ -20,6 +20,7 @@ nav: - Getting Started: 'getting-started.md' - Reference: 'reference.md' - Methods: 'methods.md' + - Philosophy: 'philosophy.md' - Examples: "examples.md" extra_css: - overrides/css/extra.css From 90440f83ab342430613ed8939b04f709dddae807 Mon Sep 17 00:00:00 2001 From: Seniister Date: Sun, 17 Jul 2022 13:11:25 +0300 Subject: [PATCH 04/10] new origin --- PlayGround/Controllers/Default.cs | 27 +- ShiftGrid.Core/docs/examples.md | 465 ++++++++++++++++++++++-------- Test.Shared/Tests/Filters.cs | 2 +- 3 files changed, 365 insertions(+), 129 deletions(-) diff --git a/PlayGround/Controllers/Default.cs b/PlayGround/Controllers/Default.cs index 3285b19..4762146 100644 --- a/PlayGround/Controllers/Default.cs +++ b/PlayGround/Controllers/Default.cs @@ -195,7 +195,7 @@ await db //It's better to use nameof. When targetting fields in Filters and Columns. return Ok(shiftGrid); } - [HttpPost("filters_equals")] + [HttpPost("filters_or")] public async Task Filters_Equals() { var db = new DB(); @@ -216,13 +216,26 @@ await db .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig { Filters = new List { - new GridFilter - { - Field = nameof(Employee.ID), - Operator = GridFilterOperator.Equals, - Value = 1 + new GridFilter{ + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = "1", + OR = new List { + new GridFilter + { + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = "5" + }, + new GridFilter + { + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = "12" + } } - } + } + } }); //It's better to use nameof. When targetting fields in Filters and Columns. diff --git a/ShiftGrid.Core/docs/examples.md b/ShiftGrid.Core/docs/examples.md index c24ea01..edb4040 100644 --- a/ShiftGrid.Core/docs/examples.md +++ b/ShiftGrid.Core/docs/examples.md @@ -1,137 +1,360 @@ ### Filtering -There are many ways of filtering. Here are some examples of it. +There are many ways of filtering, for filtering an object of [`GridFilter`](/reference/#gridfilter) is required. Here are some examples of it. #### Equals `Equals` can be used to get only one record with the given specification. -``` C# -[HttpPost("filters")] - public async Task Filters() - { - var db = new DB(); +=== "C#" + ``` C# + [HttpPost("filters")] + public async Task Filters() + { + var db = new DB(); - var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; - var shiftGrid = - await db - .Employees - .Select(x => new - { - x.ID, - x.FirstName, - x.LastName, - x.Birthdate, - Department = x.Department.Name - }) - .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig - { - Filters = new List { - new GridFilter - { - Field = nameof(Employee.ID), - Operator = GridFilterOperator.Equals, - Value = 1 + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = 1 + } } - } - }); + }); - //It's better to use nameof. When targetting fields in Filters and Columns. - return Ok(shiftGrid); + //It's better to use nameof. When targetting fields in Filters and Columns. + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[Name] AS [Department] + FROM [Employees] AS [e] + LEFT JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[ID] + WHERE [e].[ID] = CAST(1 AS bigint) + ORDER BY [e].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "filters": [ + { + "field": "ID", + "operator": "=", + "value" : 1 + } + ], + "columns": [], + "pagination": { + "pageSize": 10 } -``` -The above example (when using EF Core and SQL Server) generates an SQL like below -``` SQL -SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[Name] AS [Department] -FROM [Employees] AS [e] -LEFT JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[ID] -WHERE [e].[ID] = CAST(1 AS bigint) -ORDER BY [e].[ID] -``` -#### In -`In` can be used to get multiple records with the given specification. -``` C# -[HttpPost("filters")] - public async Task Filters() - { - var db = new DB(); + } + ``` +=== "Response" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "department": "IT" + } + ], + "aggregate": null, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [ + { + "field": "ID", + "operator": "=", + "value": 1, + "or": null + } + ], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": true, + "order": 1 + }, + { + "headerText": "LastName", + "field": "LastName", + "visible": true, + "order": 2 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 3 + }, + { + "headerText": "Department", + "field": "Department", + "visible": true, + "order": 4 + } + ], + "pagination": { + "count": 1, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 0, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": false, + "lastPageIndex": 0, + "dataStart": 1, + "dataEnd": 1 + }, + "beforeLoadingData": "2022-07-17T08:54:52.9137933Z", + "afterLoadingData": "2022-07-17T08:54:52.9196707Z" + } + ``` +#### Or +`Or` can be used for multiple filtering options that will be Or ed with the current filtering options. +=== "C#" + ``` C# + [HttpPost("filters_or")] + public async Task Filters() + { + var db = new DB(); - var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; - var shiftGrid = - await db - .Employees - .Select(x => new - { - x.ID, - x.FirstName, - x.LastName, - x.Birthdate, - Department = x.Department.Name - }) - .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig - { - Filters = new List { - new GridFilter - { - Field = nameof(Employee.ID), - Operator = GridFilterOperator.In, - Value = new List { 1, 4, 10 } - } - } - }); + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig { + Filters = new List { + new GridFilter{ + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = "1", + OR = new List { + new GridFilter + { + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = "5" + }, + new GridFilter + { + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = "12" + } + } + } + } + }); - //It's better to use nameof. When targetting fields in Filters and Columns. - return Ok(shiftGrid); + //It's better to use nameof. When targetting fields in Filters and Columns. + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[Name] AS [Department] + FROM [Employees] AS [e] + LEFT JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[ID] + WHERE [e].[ID] IN (CAST(1 AS bigint), CAST(5 AS bigint), CAST(12 AS bigint)) + ORDER BY [e].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 } -``` -The above example (when using EF Core and SQL Server) generates an SQL like below -``` SQL -SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[Name] AS [Department] -FROM [Employees] AS [e] -LEFT JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[ID] -WHERE [e].[ID] IN (CAST(1 AS bigint), CAST(4 AS bigint), CAST(10 AS bigint)) -ORDER BY [e].[ID] -``` -#### Starts With -`StartsWith` can be used to filter the data depending of what value the data begins with. -``` C# -[HttpPost("filters")] - public async Task Filters() + ], + "filters": [ { - var db = new DB(); - - var DbF = Microsoft.EntityFrameworkCore.EF.Functions; - - var shiftGrid = - await db - .Employees - .Select(x => new + "field": "ID", + "operator": "=", + "value" : 1, + "or": [ + { + "field": "ID", + "operator": "=", + "value" : 5 + }, + { + "field": "ID", + "operator": "=", + "value" : 12 + } + ] + } + ], + "columns": [], + "pagination": { + "pageSize": 10 + } + } + ``` +=== "Response" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 3, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "department": "IT" + }, + { + "id": 5, + "firstName": "First Name (5)", + "lastName": "Last Name (5)", + "birthdate": "1955-03-02T00:00:00", + "department": "Marketing" + }, + { + "id": 12, + "firstName": "First Name (12)", + "lastName": "Last Name (12)", + "birthdate": "1955-06-15T00:00:00", + "department": "Customer Support" + } + ], + "aggregate": null, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [ + { + "field": "ID", + "operator": "=", + "value": "1", + "or": [ { - x.ID, - x.FirstName, - x.LastName, - x.Birthdate, - Department = x.Department.Name - }) - .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + "field": "ID", + "operator": "=", + "value": "5", + "or": null + }, { - Filters = new List { - new GridFilter - { - Field = nameof(Employee.FirstName), - Operator = GridFilterOperator.StartsWith, - Value = "First Name (1" - } - } - }); - - //It's better to use nameof. When targetting fields in Filters and Columns. - return Ok(shiftGrid); + "field": "ID", + "operator": "=", + "value": "12", + "or": null + } + ] } -``` -The above example (when using EF Core and SQL Server) generates an SQL like below -``` SQL -SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[Name] AS [Department] -FROM [Employees] AS [e] -LEFT JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[ID] -WHERE [e].[FirstName] LIKE N'First Name (1%' -ORDER BY [e].[ID] -``` + ], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": true, + "order": 1 + }, + { + "headerText": "LastName", + "field": "LastName", + "visible": true, + "order": 2 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 3 + }, + { + "headerText": "Department", + "field": "Department", + "visible": true, + "order": 4 + } + ], + "pagination": { + "count": 1, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 0, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": false, + "lastPageIndex": 0, + "dataStart": 1, + "dataEnd": 3 + }, + "beforeLoadingData": "2022-07-17T09:15:15.9393452Z", + "afterLoadingData": "2022-07-17T09:15:15.9884659Z" + } + ``` +???+ note + + Using multiple filters while the filtering operator is equals as the same as using `IN` operator for filtering multiple values diff --git a/Test.Shared/Tests/Filters.cs b/Test.Shared/Tests/Filters.cs index d45929b..024f590 100644 --- a/Test.Shared/Tests/Filters.cs +++ b/Test.Shared/Tests/Filters.cs @@ -273,7 +273,7 @@ public async Task Filters_Or_Equals() } } } - } + } }); Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(shiftGrid, Newtonsoft.Json.Formatting.Indented)); From 3a621d3a55a3f9cef789ee6b68b4409607041584 Mon Sep 17 00:00:00 2001 From: Seniister Date: Sun, 17 Jul 2022 17:04:26 +0300 Subject: [PATCH 05/10] Examples --- PlayGround/Controllers/Default.cs | 24 +-- ShiftGrid.Core/docs/examples.md | 291 +++++++++++++++++++++++++++++- 2 files changed, 294 insertions(+), 21 deletions(-) diff --git a/PlayGround/Controllers/Default.cs b/PlayGround/Controllers/Default.cs index 4762146..bab88b7 100644 --- a/PlayGround/Controllers/Default.cs +++ b/PlayGround/Controllers/Default.cs @@ -86,7 +86,7 @@ await db x.FirstName, x.LastName, x.Birthdate, - x.DepartmentId, + x.Department, }) .ToShiftGridAsync("ID", SortDirection.Ascending, gridConfig); @@ -155,15 +155,11 @@ await db } } }); - - - //Hiding the department will also ommit the Join that's made to the Department table. This should also be shown clearly in the doc - return Ok(shiftGrid); } - [HttpPost("filters")] - public async Task Filters() + [HttpPost("filters_equals")] + public async Task Filters_Equals() { var db = new DB(); @@ -196,7 +192,7 @@ await db return Ok(shiftGrid); } [HttpPost("filters_or")] - public async Task Filters_Equals() + public async Task Filters_Equa() { var db = new DB(); @@ -223,15 +219,15 @@ await db OR = new List { new GridFilter { - Field = nameof(Employee.ID), - Operator = GridFilterOperator.Equals, - Value = "5" + Field = nameof(Employee.FirstName), + Operator = GridFilterOperator.EndsWith, + Value = "2)" }, new GridFilter { - Field = nameof(Employee.ID), - Operator = GridFilterOperator.Equals, - Value = "12" + Field = nameof(Employee.FirstName), + Operator = GridFilterOperator.StartsWith, + Value = "First Name (3" } } } diff --git a/ShiftGrid.Core/docs/examples.md b/ShiftGrid.Core/docs/examples.md index edb4040..2dbb7aa 100644 --- a/ShiftGrid.Core/docs/examples.md +++ b/ShiftGrid.Core/docs/examples.md @@ -1,10 +1,11 @@ ### Filtering -There are many ways of filtering, for filtering an object of [`GridFilter`](/reference/#gridfilter) is required. Here are some examples of it. +There are many ways of filtering, an object of [`GridFilter`](/reference/#gridfilter) is required. if multiple [`GridFilter`](/reference/#gridfilter) is given the filters will be AND ed. +The follwings are some exmaples. #### Equals `Equals` can be used to get only one record with the given specification. === "C#" - ``` C# - [HttpPost("filters")] + ``` C# hl_lines="21 22 23 24 25 26 27 28" + [HttpPost("filters_equals")] public async Task Filters() { var db = new DB(); @@ -47,7 +48,7 @@ There are many ways of filtering, for filtering an object of [`GridFilter`](/ref ORDER BY [e].[ID] ``` === "Request" - ``` JSON + ``` JSON hl_lines="10 11 12 13 14 15 16" { "dataPageIndex": 0, "dataPageSize": 5, @@ -70,8 +71,33 @@ There are many ways of filtering, for filtering an object of [`GridFilter`](/ref } } ``` -=== "Response" - ``` JSON +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "department": "IT" + } + ], + "aggregate": null, + "sort": [...], + "stableSort": {...}, + "filters": [...], + "columns": [...], + "pagination": {...}, + "beforeLoadingData": "2022-07-17T08:54:52.9137933Z", + "afterLoadingData": "2022-07-17T08:54:52.9196707Z" + } + ``` +=== "Response (Full)" + ``` JSON hl_lines="25 26 27 28 29 30 31 32" { "dataPageIndex": 0, "dataPageSize": 20, @@ -246,7 +272,46 @@ There are many ways of filtering, for filtering an object of [`GridFilter`](/ref } } ``` -=== "Response" +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 3, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "department": "IT" + }, + { + "id": 5, + "firstName": "First Name (5)", + "lastName": "Last Name (5)", + "birthdate": "1955-03-02T00:00:00", + "department": "Marketing" + }, + { + "id": 12, + "firstName": "First Name (12)", + "lastName": "Last Name (12)", + "birthdate": "1955-06-15T00:00:00", + "department": "Customer Support" + } + ], + "aggregate": null, + "sort": [...], + "stableSort": {...}, + "filters": [...], + "columns": [...], + "pagination": {...}, + "beforeLoadingData": "2022-07-17T09:15:15.9393452Z", + "afterLoadingData": "2022-07-17T09:15:15.9884659Z" + } + ``` +=== "Response (Full)" ``` JSON { "dataPageIndex": 0, @@ -358,3 +423,215 @@ There are many ways of filtering, for filtering an object of [`GridFilter`](/ref ???+ note Using multiple filters while the filtering operator is equals as the same as using `IN` operator for filtering multiple values + +### Grid Column Excluding +A column can be excluded in the generated SQL query using the [`GridColumn`](/reference/#gridcolumn) object when visible is set to false, if the column comes from a table join, the join will be omitted + +=== "C#" + ``` C# + [HttpPost("columns")] + public async Task Columns() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "FirstName", + Visible = false + }, + new GridColumn + { + Field = "Department", + Visible = false + } + } + }); + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [e].[ID], NULL AS [FirstName], [e].[LastName], [e].[Birthdate] + FROM [Employees] AS [e] + ORDER BY [e].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "columns": [ + { + "field":"FirstName", + "visible":false + }, + { + "field":"Department", + "visible":false + } + + ], + "pagination": { + "pageSize": 10 + }, + "filters": [ + ] + } + ``` +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "dataCount": 1000, + "data": [ + { + "id": 1, + "firstName": null, + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "department": null + }, + ... + ], + "aggregate": null, + "sort": [...], + "stableSort": {...}, + "filters": [], + "columns": [...], + "pagination": {...}, + "beforeLoadingData": "2022-07-17T13:35:54.5310457Z", + "afterLoadingData": "2022-07-17T13:35:54.5351803Z" + } + ``` +=== "Response (Full)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "dataCount": 1000, + "data": [ + { + "id": 1, + "firstName": null, + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "department": null + }, + { + "id": 2, + "firstName": null, + "lastName": "Last Name (2)", + "birthdate": "1955-01-16T00:00:00", + "department": null + }, + { + "id": 3, + "firstName": null, + "lastName": "Last Name (3)", + "birthdate": "1955-01-31T00:00:00", + "department": null + }, + { + "id": 4, + "firstName": null, + "lastName": "Last Name (4)", + "birthdate": "1955-02-15T00:00:00", + "department": null + }, + { + "id": 5, + "firstName": null, + "lastName": "Last Name (5)", + "birthdate": "1955-03-02T00:00:00", + "department": null + } + ], + "aggregate": null, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": false, + "order": 1 + }, + { + "headerText": "LastName", + "field": "LastName", + "visible": true, + "order": 2 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 3 + }, + { + "headerText": "Department", + "field": "Department", + "visible": false, + "order": 4 + } + ], + "pagination": { + "count": 200, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 9, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": true, + "lastPageIndex": 199, + "dataStart": 1, + "dataEnd": 5 + }, + "beforeLoadingData": "2022-07-17T13:47:40.8863074Z", + "afterLoadingData": "2022-07-17T13:47:40.8881376Z" + } + ``` + +???+ warning + + The `select()` method must exist in the c# code for the columns to be omitted successfully. + From 014a02c7fe26144961c514ed131ab0a1235917ac Mon Sep 17 00:00:00 2001 From: Sarmad <80126439+Seniister@users.noreply.github.com> Date: Mon, 18 Jul 2022 15:16:03 +0300 Subject: [PATCH 06/10] Delete ShiftGrid.postman_collection.json --- ShiftGrid.postman_collection.json | 193 ------------------------------ 1 file changed, 193 deletions(-) delete mode 100644 ShiftGrid.postman_collection.json diff --git a/ShiftGrid.postman_collection.json b/ShiftGrid.postman_collection.json deleted file mode 100644 index 55c58cb..0000000 --- a/ShiftGrid.postman_collection.json +++ /dev/null @@ -1,193 +0,0 @@ -{ - "info": { - "_postman_id": "f1642c49-18d4-4dd0-9ad9-65a40148c5cd", - "name": "ShiftGrid", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "5139868" - }, - "item": [ - { - "name": "Basic", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"dataPageIndex\": 0,\r\n \"dataPageSize\": 5,\r\n \"sort\": [\r\n {\r\n \"field\": \"ID\",\r\n \"sortDirection\": 0\r\n }\r\n ],\r\n \"columns\": [],\r\n \"pagination\": {\r\n \"pageSize\": 10\r\n },\r\n \"filters\": [\r\n \r\n ]\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{ShiftGridHost}}/api/basic", - "host": [ - "{{ShiftGridHost}}" - ], - "path": [ - "api", - "basic" - ] - } - }, - "response": [] - }, - { - "name": "Aggregate", - "request": { - "method": "POST", - "header": [ - { - "key": "database", - "value": "SqlServer", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"dataPageIndex\": 0,\r\n \"dataPageSize\": 5,\r\n \"sort\": [\r\n {\r\n \"field\": \"ID\",\r\n \"sortDirection\": 0\r\n }\r\n ],\r\n \"columns\": [],\r\n \"pagination\": {\r\n \"pageSize\": 10\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{ShiftGridHost}}/api/aggregate", - "host": [ - "{{ShiftGridHost}}" - ], - "path": [ - "api", - "aggregate" - ] - } - }, - "response": [] - }, - { - "name": "Columns", - "request": { - "method": "POST", - "header": [ - { - "key": "database", - "value": "SqlServer", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"dataPageIndex\": 0,\r\n \"dataPageSize\": 5,\r\n \"sort\": [\r\n {\r\n \"field\": \"ID\",\r\n \"sortDirection\": 0\r\n }\r\n ],\r\n \"columns\": [],\r\n \"pagination\": {\r\n \"pageSize\": 10\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{ShiftGridHost}}/api/columns", - "host": [ - "{{ShiftGridHost}}" - ], - "path": [ - "api", - "columns" - ] - } - }, - "response": [] - }, - { - "name": "Filters", - "request": { - "method": "POST", - "header": [ - { - "key": "database", - "value": "SqlServer", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"dataPageIndex\": 0,\r\n \"dataPageSize\": 5,\r\n \"sort\": [\r\n {\r\n \"field\": \"ID\",\r\n \"sortDirection\": 0\r\n }\r\n ],\r\n \"columns\": [],\r\n \"pagination\": {\r\n \"pageSize\": 10\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{ShiftGridHost}}/api/filters", - "host": [ - "{{ShiftGridHost}}" - ], - "path": [ - "api", - "filters" - ] - } - }, - "response": [] - }, - { - "name": "No Config", - "request": { - "method": "POST", - "header": [ - { - "key": "database", - "value": "SqlServer", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"dataPageIndex\": 0,\r\n \"dataPageSize\": 5,\r\n \"sort\": [\r\n {\r\n \"field\": \"ID\",\r\n \"sortDirection\": 0\r\n }\r\n ],\r\n \"columns\": [],\r\n \"pagination\": {\r\n \"pageSize\": 10\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{ShiftGridHost}}/api/no-config", - "host": [ - "{{ShiftGridHost}}" - ], - "path": [ - "api", - "no-config" - ] - } - }, - "response": [] - }, - { - "name": "Insert Test Data", - "request": { - "method": "POST", - "header": [ - { - "key": "database", - "value": "SqlServer", - "type": "text" - } - ], - "url": { - "raw": "{{ShiftGridHost}}/api/insert-test-data", - "host": [ - "{{ShiftGridHost}}" - ], - "path": [ - "api", - "insert-test-data" - ] - } - }, - "response": [] - } - ] -} \ No newline at end of file From 04b52a877d568e7246be6bc52c905f4431ae32dd Mon Sep 17 00:00:00 2001 From: Sarmad Date: Mon, 18 Jul 2022 23:25:31 +0300 Subject: [PATCH 07/10] More Column examples --- PlayGround/Controllers/Default.cs | 130 ++++- ShiftGrid.Core/docs/examples.md | 764 +++++++++++++++++++++++++++++- 2 files changed, 890 insertions(+), 4 deletions(-) diff --git a/PlayGround/Controllers/Default.cs b/PlayGround/Controllers/Default.cs index bab88b7..64c2f89 100644 --- a/PlayGround/Controllers/Default.cs +++ b/PlayGround/Controllers/Default.cs @@ -86,7 +86,7 @@ await db x.FirstName, x.LastName, x.Birthdate, - x.Department, + Department = x.Department.Name }) .ToShiftGridAsync("ID", SortDirection.Ascending, gridConfig); @@ -157,6 +157,134 @@ await db }); return Ok(shiftGrid); } + [HttpPost("columns-exclude-collections")] + public async Task Columns_Exclude_Collections() + { + var db = new DB(); + + var shiftGrid = + await db + .Departments + .Select(x => new + { + x.ID, + x.Name, + Employee = x.Employees, + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "Employee", + Visible = false + }, + } + }); + + return Ok(shiftGrid); + } + [HttpPost("columns-exclude-identical")] + public async Task Columns_Exclude_Identical() + { + var db = new DB(); + + var shiftGrid = + await db + .Departments + .Select(x => new + { + x.ID, + x.Name, + Employee = x.Employees.Select(y => new + { + Department = y.Department.Name + }), + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "Name", + Visible = false + }, + } + }); + + return Ok(shiftGrid); + } + [HttpPost("columns-exclude-annynomous-object")] + public async Task Columns_Exclude_AnnonymousObject() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + FullName = x.FirstName + x.LastName, + x.Birthdate, + x.DepartmentId + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "FullName", + Visible = false + }, + } + }); + return Ok(shiftGrid); + } + [HttpPost("columns-exclude-field-in-summary")] + public async Task Columns_Exclude_AFieldThatsInSummary() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + x.DepartmentId + }) + .SelectAggregate(x => new + { + Count = x.Count(), + TotalDepartmentId = x.Sum(y => y.DepartmentId), + MaxDepartmentId = x.Max(y => y.DepartmentId) + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "DepartmentId", + Visible = false + }, + } + }); + return Ok(shiftGrid); + } [HttpPost("filters_equals")] public async Task Filters_Equals() diff --git a/ShiftGrid.Core/docs/examples.md b/ShiftGrid.Core/docs/examples.md index 2dbb7aa..ed22df7 100644 --- a/ShiftGrid.Core/docs/examples.md +++ b/ShiftGrid.Core/docs/examples.md @@ -424,7 +424,7 @@ The follwings are some exmaples. Using multiple filters while the filtering operator is equals as the same as using `IN` operator for filtering multiple values -### Grid Column Excluding +### Grid Column exclusion A column can be excluded in the generated SQL query using the [`GridColumn`](/reference/#gridcolumn) object when visible is set to false, if the column comes from a table join, the join will be omitted === "C#" @@ -630,8 +630,766 @@ A column can be excluded in the generated SQL query using the [`GridColumn`](/re "afterLoadingData": "2022-07-17T13:47:40.8881376Z" } ``` - ???+ warning + the `select` method must exist for the exclusion to be done successfully +???+ info + if the excluded column is the same as the one used for sorting its value will be 0 not null, in our exampe if ID is excluded it will be 0. +#### Excluding Collections +Collections can be excluded, if the collection comes from table join the join will be omitted too. + +=== "C#" + ``` C# + [HttpPost("columns-exclude-collections")] + public async Task Columns_Exclude_Collections() + { + var db = new DB(); + + var shiftGrid = + await db + .Departments + .Select(x => new + { + x.ID, + x.Name, + Employee = x.Employees, + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "Employee", + Visible = false + }, + } + }); + + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [d].[ID], [d].[Name] + FROM [Departments] AS [d] + ORDER BY [d].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "columns": [ + { + "field": "Employee", + "visible": false + } + ], + "pagination": { + "pageSize": 10 + } + } + ``` +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "dataCount": 6, + "data": [ + { + "id": 1, + "name": "IT", + "employee": null + }, + { + "id": 2, + "name": "Finance", + "employee": null + }, + { + "id": 3, + "name": "HR", + "employee": null + }, + { + "id": 4, + "name": "Sales", + "employee": null + }, + { + "id": 5, + "name": "Marketing", + "employee": null + } + ], + "aggregate": null, + "sort": [...], + "stableSort": {...}, + "filters": [], + "columns": [...], + "pagination": {...}, + "beforeLoadingData": "2022-07-18T18:46:12.2480272Z", + "afterLoadingData": "2022-07-18T18:46:12.2493327Z" + } + ``` +=== "Response (Full)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "dataCount": 6, + "data": [ + { + "id": 1, + "name": "IT", + "employee": null + }, + { + "id": 2, + "name": "Finance", + "employee": null + }, + { + "id": 3, + "name": "HR", + "employee": null + }, + { + "id": 4, + "name": "Sales", + "employee": null + }, + { + "id": 5, + "name": "Marketing", + "employee": null + } + ], + "aggregate": null, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": "Name", + "field": "Name", + "visible": true, + "order": 1 + }, + { + "headerText": "Employee", + "field": "Employee", + "visible": false, + "order": 2 + } + ], + "pagination": { + "count": 2, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 1, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": false, + "lastPageIndex": 1, + "dataStart": 1, + "dataEnd": 5 + }, + "beforeLoadingData": "2022-07-18T18:46:12.2480272Z", + "afterLoadingData": "2022-07-18T18:46:12.2493327Z" + } + ``` +#### Excluding identical columns +Two identical column, one is a normal column and the other one is inside the collection. + +=== "C#" + ``` C# + [HttpPost("columns-exclude-identical")] + public async Task Columns_Exclude_Identical() + { + var db = new DB(); + + var shiftGrid = + await db + .Departments + .Select(x => new + { + x.ID, + x.Name, + Employee = x.Employees.Select(y => new + { + Department = y.Department.Name + }), + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "Name", + Visible = false + }, + } + }); + + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [d].[ID], [t].[Department], [t].[ID], [t].[ID0] + FROM [Departments] AS [d] + LEFT JOIN ( + SELECT [d0].[Name] AS [Department], [e].[ID], [d0].[ID] AS [ID0], [e].[DepartmentId] + FROM [Employees] AS [e] + LEFT JOIN [Departments] AS [d0] ON [e].[DepartmentId] = [d0].[ID] + ) AS [t] ON [d].[ID] = [t].[DepartmentId] + ORDER BY [d].[ID], [t].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "columns": [ + { + "field": "Department", + "visible": false + } + ], + "pagination": { + "pageSize": 10 + } + } + ``` +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 6, + "data": [ + { + "id": 1, + "name": null, + "employee": [ + { + "department": "IT" + }, + ... + ] + }, + ... + ], + "aggregate": null, + "sort": [...], + "stableSort": {...}, + "filters": [], + "columns": [...], + "pagination": {...}, + "beforeLoadingData": "2022-07-18T19:24:05.3233637Z", + "afterLoadingData": "2022-07-18T19:24:05.4283594Z" + } + ``` +=== "Response (Full)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 6, + "data": [ + { + "id": 1, + "name": null, + "employee": [ + { + "department": "IT" + }, + ... + ] + }, + { + "id": 2, + "name": null, + "employee": [ + { + "department": "Finance" + }, + ... + ] + }, + { + "id": 3, + "name": null, + "employee": [ + { + "department": "HR" + }, + ... + ] + }, + { + "id": 4, + "name": null, + "employee": [ + { + "department": "Sales" + }, + ... + ] + }, + { + "id": 5, + "name": null, + "employee": [ + { + "department": "Marketing" + }, + ... + ] + }, + { + "id": 6, + "name": null, + "employee": [ + { + "department": "Customer Support" + }, + ... + ] + } + ], + "aggregate": null, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": "Name", + "field": "Name", + "visible": false, + "order": 1 + }, + { + "headerText": "Employee", + "field": "Employee", + "visible": true, + "order": 2 + } + ], + "pagination": { + "count": 1, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 0, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": false, + "lastPageIndex": 0, + "dataStart": 1, + "dataEnd": 6 + }, + "beforeLoadingData": "2022-07-18T19:24:05.3233637Z", + "afterLoadingData": "2022-07-18T19:24:05.4283594Z" + } + ``` +#### Excluding Annonymous Object - The `select()` method must exist in the c# code for the columns to be omitted successfully. +=== "C#" + ``` C# + [HttpPost("columns-exclude-annynomous-object")] + public async Task Columns_Exclude_AnnonymousObject() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + FullName = x.FirstName + x.LastName, + x.Birthdate, + x.DepartmentId + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "FullName", + Visible = false + }, + } + }); + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [e].[ID], [e].[FirstName], [e].[LastName], NULL AS [FullName], [e].[Birthdate], [e].[DepartmentId] + FROM [Employees] AS [e] + ORDER BY [e].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "columns": [ + { + "field": "FullName", + "visible": false + } + ], + "pagination": { + "pageSize": 10 + } + } + ``` +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1000, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "fullName": null, + "birthdate": "1955-01-01T00:00:00", + "departmentId": 1 + }, + ... + ], + "aggregate": null, + "sort": [...], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [], + "columns": [...], + "pagination": {...}, + "beforeLoadingData": "2022-07-18T19:48:09.0032974Z", + "afterLoadingData": "2022-07-18T19:48:09.1028997Z" + } + ``` +=== "Response (Full)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1000, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "fullName": null, + "birthdate": "1955-01-01T00:00:00", + "departmentId": 1 + }, + ... + ], + "aggregate": null, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": true, + "order": 1 + }, + { + "headerText": "LastName", + "field": "LastName", + "visible": true, + "order": 2 + }, + { + "headerText": "FullName", + "field": "FullName", + "visible": false, + "order": 3 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 4 + }, + { + "headerText": "DepartmentId", + "field": "DepartmentId", + "visible": true, + "order": 5 + } + ], + "pagination": { + "count": 50, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 9, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": true, + "lastPageIndex": 49, + "dataStart": 1, + "dataEnd": 20 + }, + "beforeLoadingData": "2022-07-18T19:48:09.0032974Z", + "afterLoadingData": "2022-07-18T19:48:09.1028997Z" + } + ``` +#### Excluding a column that is in summary + +=== "C#" + ``` C# + [HttpPost("columns-exclude-field-in-summary")] + public async Task Columns_Exclude_AFieldThatsInSummary() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + x.DepartmentId + }) + .SelectAggregate(x => new + { + Count = x.Count(), + TotalDepartmentId = x.Sum(y => y.DepartmentId), + MaxDepartmentId = x.Max(y => y.DepartmentId) + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "DepartmentId", + Visible = false + }, + } + }); + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate] + FROM [Employees] AS [e] + ORDER BY [e].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "columns": [ + { + "field": "DepartmentId", + "visible": false + } + ], + "pagination": { + "pageSize": 10 + } + } + ``` +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1000, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "departmentId": null + }, + ... + ], + "aggregate": { + "count": 1000, + "totalDepartmentId": null, + "maxDepartmentId": null + }, + "sort": [...], + "stableSort": {...}, + "filters": [], + "columns": [...], + "pagination": {...}, + "beforeLoadingData": "2022-07-18T20:04:43.3240903Z", + "afterLoadingData": "2022-07-18T20:04:43.3687013Z" + } + ``` +=== "Response (Full)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1000, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "departmentId": null + }, + ... + ], + "aggregate": { + "count": 1000, + "totalDepartmentId": null, + "maxDepartmentId": null + }, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": true, + "order": 1 + }, + { + "headerText": "LastName", + "field": "LastName", + "visible": true, + "order": 2 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 3 + }, + { + "headerText": "DepartmentId", + "field": "DepartmentId", + "visible": false, + "order": 4 + } + ], + "pagination": { + "count": 50, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 9, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": true, + "lastPageIndex": 49, + "dataStart": 1, + "dataEnd": 20 + }, + "beforeLoadingData": "2022-07-18T20:04:43.3240903Z", + "afterLoadingData": "2022-07-18T20:04:43.3687013Z" + } + ``` From fb39b1b75ac01e4decc56299ff995f9314dabed2 Mon Sep 17 00:00:00 2001 From: Sarmad Date: Tue, 19 Jul 2022 14:53:48 +0300 Subject: [PATCH 08/10] More examples --- PlayGround/Controllers/Default.cs | 81 ++++- PlayGround/Properties/launchSettings.json | 13 +- ShiftGrid.Core/docs/examples.md | 419 ++++++++++++++++++++++ 3 files changed, 502 insertions(+), 11 deletions(-) diff --git a/PlayGround/Controllers/Default.cs b/PlayGround/Controllers/Default.cs index 64c2f89..2ded951 100644 --- a/PlayGround/Controllers/Default.cs +++ b/PlayGround/Controllers/Default.cs @@ -83,10 +83,10 @@ await db .Select(x => new { x.ID, - x.FirstName, + x.FirstName, x.LastName, x.Birthdate, - Department = x.Department.Name + x.Department }) .ToShiftGridAsync("ID", SortDirection.Ascending, gridConfig); @@ -285,7 +285,50 @@ await db }); return Ok(shiftGrid); } + class SummaryModel + { + public int Count { get; set; } + public long? TotalDepartmentId { get; set; } + public long? MaxDepartmentId { get; set; } + } + [HttpPost("columns-exclude-field-in-summary-using-a-model")] + public async Task Columns_Exclude_AFieldThatsInSummary_UsingAModel() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + x.DepartmentId + }) + .SelectAggregate(x => new SummaryModel + { + Count = x.Count(), + TotalDepartmentId = x.Sum(y => y.DepartmentId), + MaxDepartmentId = x.Max(y => y.DepartmentId) + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "DepartmentId", + Visible = false + }, + } + }); + return Ok(shiftGrid); + } + [HttpPost("filters_equals")] public async Task Filters_Equals() { @@ -320,7 +363,7 @@ await db return Ok(shiftGrid); } [HttpPost("filters_or")] - public async Task Filters_Equa() + public async Task Filters_Or() { var db = new DB(); @@ -398,6 +441,38 @@ await db //It's better to use nameof. When targetting fields in Filters and Columns. return Ok(shiftGrid); } + [HttpPost("filters_subitems")] + public async Task Filters_SubItems() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + x.Department + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = "Department.Name", + Operator = GridFilterOperator.Equals, + Value = "IT" + } + } + }); + + return Ok(shiftGrid); + } [FileHelpers.DelimitedRecord(",")] public class EmployeeCSV diff --git a/PlayGround/Properties/launchSettings.json b/PlayGround/Properties/launchSettings.json index 0ebe31f..2ba485d 100644 --- a/PlayGround/Properties/launchSettings.json +++ b/PlayGround/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "$schema": "https://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, @@ -11,21 +11,18 @@ "profiles": { "PlayGround": { "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "launchUrl": "", - "applicationUrl": "http://localhost:5124", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - } + }, + "applicationUrl": "http://localhost:5124", + "dotnetRunMessages": true }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, - "launchUrl": "", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } -} +} \ No newline at end of file diff --git a/ShiftGrid.Core/docs/examples.md b/ShiftGrid.Core/docs/examples.md index ed22df7..a3c608a 100644 --- a/ShiftGrid.Core/docs/examples.md +++ b/ShiftGrid.Core/docs/examples.md @@ -424,6 +424,236 @@ The follwings are some exmaples. Using multiple filters while the filtering operator is equals as the same as using `IN` operator for filtering multiple values +#### Filtering subitems + +=== "C#" + ``` C# + [HttpPost("filters_subitems")] + public async Task Filters_SubItems() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + x.Department + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = "Department.Name", + Operator = GridFilterOperator.Equals, + Value = "IT" + } + } + }); + + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[Name] AS [Department] + FROM [Employees] AS [e] + LEFT JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[ID] + WHERE [e].[ID] IN (CAST(1 AS bigint), CAST(5 AS bigint), CAST(12 AS bigint)) + ORDER BY [e].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "filters": [ + { + "field": "ID", + "operator": "=", + "value" : 1, + "or": [ + { + "field": "ID", + "operator": "=", + "value" : 5 + }, + { + "field": "ID", + "operator": "=", + "value" : 12 + } + ] + } + ], + "columns": [], + "pagination": { + "pageSize": 10 + } + } + ``` +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 3, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "department": "IT" + }, + { + "id": 5, + "firstName": "First Name (5)", + "lastName": "Last Name (5)", + "birthdate": "1955-03-02T00:00:00", + "department": "Marketing" + }, + { + "id": 12, + "firstName": "First Name (12)", + "lastName": "Last Name (12)", + "birthdate": "1955-06-15T00:00:00", + "department": "Customer Support" + } + ], + "aggregate": null, + "sort": [...], + "stableSort": {...}, + "filters": [...], + "columns": [...], + "pagination": {...}, + "beforeLoadingData": "2022-07-17T09:15:15.9393452Z", + "afterLoadingData": "2022-07-17T09:15:15.9884659Z" + } + ``` +=== "Response (Full)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 3, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "department": "IT" + }, + { + "id": 5, + "firstName": "First Name (5)", + "lastName": "Last Name (5)", + "birthdate": "1955-03-02T00:00:00", + "department": "Marketing" + }, + { + "id": 12, + "firstName": "First Name (12)", + "lastName": "Last Name (12)", + "birthdate": "1955-06-15T00:00:00", + "department": "Customer Support" + } + ], + "aggregate": null, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [ + { + "field": "ID", + "operator": "=", + "value": "1", + "or": [ + { + "field": "ID", + "operator": "=", + "value": "5", + "or": null + }, + { + "field": "ID", + "operator": "=", + "value": "12", + "or": null + } + ] + } + ], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": true, + "order": 1 + }, + { + "headerText": "LastName", + "field": "LastName", + "visible": true, + "order": 2 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 3 + }, + { + "headerText": "Department", + "field": "Department", + "visible": true, + "order": 4 + } + ], + "pagination": { + "count": 1, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 0, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": false, + "lastPageIndex": 0, + "dataStart": 1, + "dataEnd": 3 + }, + "beforeLoadingData": "2022-07-17T09:15:15.9393452Z", + "afterLoadingData": "2022-07-17T09:15:15.9884659Z" + } + ``` + ### Grid Column exclusion A column can be excluded in the generated SQL query using the [`GridColumn`](/reference/#gridcolumn) object when visible is set to false, if the column comes from a table join, the join will be omitted @@ -1393,3 +1623,192 @@ Two identical column, one is a normal column and the other one is inside the col "afterLoadingData": "2022-07-18T20:04:43.3687013Z" } ``` +#### Excluding a column that is in summary using a model + +=== "C#" + ``` C# + class SummaryModel + { + public int Count { get; set; } + public long? TotalDepartmentId { get; set; } + public long? MaxDepartmentId { get; set; } + } + [HttpPost("columns-exclude-field-in-summary-using-a-model")] + public async Task Columns_Exclude_AFieldThatsInSummary_UsingAModel() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + x.DepartmentId + }) + .SelectAggregate(x => new SummaryModel + { + Count = x.Count(), + TotalDepartmentId = x.Sum(y => y.DepartmentId), + MaxDepartmentId = x.Max(y => y.DepartmentId) + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "DepartmentId", + Visible = false + }, + } + }); + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate] + FROM [Employees] AS [e] + ORDER BY [e].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "columns": [ + { + "field": "DepartmentId", + "visible": false + } + ], + "pagination": { + "pageSize": 10 + } + } + ``` +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1000, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "departmentId": null + }, + ... + ], + "aggregate": { + "count": 1000, + "totalDepartmentId": null, + "maxDepartmentId": null + }, + "sort": [...], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [], + "columns": [...], + "pagination": {...}, + "beforeLoadingData": "2022-07-19T11:07:58.1705378Z", + "afterLoadingData": "2022-07-19T11:07:58.2177103Z" + } + ``` +=== "Response (Full)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1000, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "departmentId": null + }, + ... + ], + "aggregate": { + "count": 1000, + "totalDepartmentId": null, + "maxDepartmentId": null + }, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": true, + "order": 1 + }, + { + "headerText": "LastName", + "field": "LastName", + "visible": true, + "order": 2 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 3 + }, + { + "headerText": "DepartmentId", + "field": "DepartmentId", + "visible": false, + "order": 4 + } + ], + "pagination": { + "count": 50, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 9, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": true, + "lastPageIndex": 49, + "dataStart": 1, + "dataEnd": 20 + }, + "beforeLoadingData": "2022-07-19T11:07:58.1705378Z", + "afterLoadingData": "2022-07-19T11:07:58.2177103Z" + } + ``` From 0fc02d54fc522830bf7e1fb08f5d693e00fcbc87 Mon Sep 17 00:00:00 2001 From: Sarmad Date: Tue, 19 Jul 2022 20:59:19 +0300 Subject: [PATCH 09/10] Filter Subitems --- PlayGround/Controllers/Default.cs | 94 +++- ShiftGrid.Core/docs/examples.md | 851 +++++++++++++++++++++++------- 2 files changed, 738 insertions(+), 207 deletions(-) diff --git a/PlayGround/Controllers/Default.cs b/PlayGround/Controllers/Default.cs index 2ded951..f090de3 100644 --- a/PlayGround/Controllers/Default.cs +++ b/PlayGround/Controllers/Default.cs @@ -329,7 +329,7 @@ await db return Ok(shiftGrid); } - [HttpPost("filters_equals")] + [HttpPost("filters-equals")] public async Task Filters_Equals() { var db = new DB(); @@ -362,7 +362,7 @@ await db //It's better to use nameof. When targetting fields in Filters and Columns. return Ok(shiftGrid); } - [HttpPost("filters_or")] + [HttpPost("filters-or")] public async Task Filters_Or() { var db = new DB(); @@ -408,7 +408,7 @@ await db //It's better to use nameof. When targetting fields in Filters and Columns. return Ok(shiftGrid); } - [HttpPost("filters_in")] + [HttpPost("filters-in")] public async Task Filters_In() { var db = new DB(); @@ -441,7 +441,7 @@ await db //It's better to use nameof. When targetting fields in Filters and Columns. return Ok(shiftGrid); } - [HttpPost("filters_subitems")] + [HttpPost("filters-subitems")] public async Task Filters_SubItems() { var db = new DB(); @@ -473,6 +473,92 @@ await db return Ok(shiftGrid); } + [HttpPost("filters-subitems-and-or")] + public async Task Filters_SubItems_AndOr() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + x.Department + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = "Department.Name", + Operator = GridFilterOperator.Equals, + Value = "IT", + OR = new List + { + new GridFilter { + Field = nameof(Employee.FirstName), + Operator = GridFilterOperator.EndsWith, + Value = "7)", + } + } + } + } + }); + + return Ok(shiftGrid); + } + [HttpPost("filters-navigated-items-and-subitems-aggregates")] + public async Task Filters_NavigatedItems_AndSubItemsAggregates() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Departments + .Select(x => new + { + x.ID, + x.Name, + Employees = x.Employees.Select(y => new + { + EmployeeID = y.ID * 10 + }) + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = "Employees.Min(EmployeeID)", + Operator = GridFilterOperator.Equals, + Value = 10, + }, + new GridFilter + { + Field = "Name", + Operator = GridFilterOperator.Equals, + Value = "IT", + }, + new GridFilter + { + Field = "Employees.Max(EmployeeID)", + Operator = GridFilterOperator.Equals, + Value = 9970, + }, + + } + }); + + return Ok(shiftGrid); + } [FileHelpers.DelimitedRecord(",")] public class EmployeeCSV diff --git a/ShiftGrid.Core/docs/examples.md b/ShiftGrid.Core/docs/examples.md index a3c608a..c9a6c89 100644 --- a/ShiftGrid.Core/docs/examples.md +++ b/ShiftGrid.Core/docs/examples.md @@ -6,38 +6,38 @@ The follwings are some exmaples. === "C#" ``` C# hl_lines="21 22 23 24 25 26 27 28" [HttpPost("filters_equals")] - public async Task Filters() - { - var db = new DB(); + public async Task Filters() + { + var db = new DB(); - var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; - var shiftGrid = - await db - .Employees - .Select(x => new - { - x.ID, - x.FirstName, - x.LastName, - x.Birthdate, - Department = x.Department.Name - }) - .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter { - Filters = new List { - new GridFilter - { - Field = nameof(Employee.ID), - Operator = GridFilterOperator.Equals, - Value = 1 - } - } - }); + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = 1 + } + } + }); - //It's better to use nameof. When targetting fields in Filters and Columns. - return Ok(shiftGrid); - } + //It's better to use nameof. When targetting fields in Filters and Columns. + return Ok(shiftGrid); + } ``` === "SQL" ``` SQL @@ -183,50 +183,50 @@ The follwings are some exmaples. === "C#" ``` C# [HttpPost("filters_or")] - public async Task Filters() - { - var db = new DB(); + public async Task Filters() + { + var db = new DB(); - var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; - var shiftGrid = - await db - .Employees - .Select(x => new - { - x.ID, - x.FirstName, - x.LastName, - x.Birthdate, - Department = x.Department.Name - }) - .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig { - Filters = new List { - new GridFilter{ - Field = nameof(Employee.ID), - Operator = GridFilterOperator.Equals, - Value = "1", - OR = new List { - new GridFilter - { - Field = nameof(Employee.ID), - Operator = GridFilterOperator.Equals, - Value = "5" - }, - new GridFilter - { - Field = nameof(Employee.ID), - Operator = GridFilterOperator.Equals, - Value = "12" - } - } - } + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig { + Filters = new List { + new GridFilter{ + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = "1", + OR = new List { + new GridFilter + { + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = "5" + }, + new GridFilter + { + Field = nameof(Employee.ID), + Operator = GridFilterOperator.Equals, + Value = "12" + } + } } - }); - - //It's better to use nameof. When targetting fields in Filters and Columns. - return Ok(shiftGrid); } + }); + + //It's better to use nameof. When targetting fields in Filters and Columns. + return Ok(shiftGrid); + } ``` === "SQL" ``` SQL @@ -428,45 +428,45 @@ The follwings are some exmaples. === "C#" ``` C# - [HttpPost("filters_subitems")] - public async Task Filters_SubItems() - { - var db = new DB(); + [HttpPost("filters_subitems")] + public async Task Filters_SubItems() + { + var db = new DB(); - var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; - var shiftGrid = - await db - .Employees - .Select(x => new - { - x.ID, - x.FirstName, - x.LastName, - x.Birthdate, - x.Department - }) - .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig - { - Filters = new List { - new GridFilter - { - Field = "Department.Name", - Operator = GridFilterOperator.Equals, - Value = "IT" - } - } - }); + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + x.Department + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = "Department.Name", + Operator = GridFilterOperator.Equals, + Value = "IT" + } + } + }); - return Ok(shiftGrid); - } + return Ok(shiftGrid); + } ``` === "SQL" ``` SQL - SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[Name] AS [Department] + SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[ID], [d].[Name] FROM [Employees] AS [e] LEFT JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[ID] - WHERE [e].[ID] IN (CAST(1 AS bigint), CAST(5 AS bigint), CAST(12 AS bigint)) + WHERE [d].[Name] = N''IT'' ORDER BY [e].[ID] ``` === "Request" @@ -482,27 +482,15 @@ The follwings are some exmaples. ], "filters": [ { - "field": "ID", + "field": "Department.Name", "operator": "=", - "value" : 1, - "or": [ - { - "field": "ID", - "operator": "=", - "value" : 5 - }, - { - "field": "ID", - "operator": "=", - "value" : 12 - } - ] - } - ], - "columns": [], - "pagination": { - "pageSize": 10 + "value":"IT" } + ], + "columns": [], + "pagination": { + "pageSize": 10 + } } ``` === "Response (Omitted)" @@ -510,38 +498,47 @@ The follwings are some exmaples. { "dataPageIndex": 0, "dataPageSize": 20, - "dataCount": 3, + "dataCount": 167, "data": [ { "id": 1, "firstName": "First Name (1)", "lastName": "Last Name (1)", "birthdate": "1955-01-01T00:00:00", - "department": "IT" + "department": { + "id": 1, + "name": "IT", + "employees": null + } }, { - "id": 5, - "firstName": "First Name (5)", - "lastName": "Last Name (5)", - "birthdate": "1955-03-02T00:00:00", - "department": "Marketing" + "id": 7, + "firstName": "First Name (7)", + "lastName": "Last Name (7)", + "birthdate": "1955-04-01T00:00:00", + "department": { + "id": 1, + "name": "IT", + "employees": null + } }, - { - "id": 12, - "firstName": "First Name (12)", - "lastName": "Last Name (12)", - "birthdate": "1955-06-15T00:00:00", - "department": "Customer Support" - } + ... ], "aggregate": null, "sort": [...], "stableSort": {...}, - "filters": [...], + "filters": [ + { + "field": "Department.Name", + "operator": "=", + "value": "IT", + "or": null + } + ], "columns": [...], "pagination": {...}, - "beforeLoadingData": "2022-07-17T09:15:15.9393452Z", - "afterLoadingData": "2022-07-17T09:15:15.9884659Z" + "beforeLoadingData": "2022-07-19T12:19:17.04074Z", + "afterLoadingData": "2022-07-19T12:19:17.1363004Z" } ``` === "Response (Full)" @@ -549,29 +546,42 @@ The follwings are some exmaples. { "dataPageIndex": 0, "dataPageSize": 20, - "dataCount": 3, + "dataCount": 167, "data": [ { "id": 1, "firstName": "First Name (1)", "lastName": "Last Name (1)", "birthdate": "1955-01-01T00:00:00", - "department": "IT" + "department": { + "id": 1, + "name": "IT", + "employees": null + } }, { - "id": 5, - "firstName": "First Name (5)", - "lastName": "Last Name (5)", - "birthdate": "1955-03-02T00:00:00", - "department": "Marketing" + "id": 7, + "firstName": "First Name (7)", + "lastName": "Last Name (7)", + "birthdate": "1955-04-01T00:00:00", + "department": { + "id": 1, + "name": "IT", + "employees": null + } }, { - "id": 12, - "firstName": "First Name (12)", - "lastName": "Last Name (12)", - "birthdate": "1955-06-15T00:00:00", - "department": "Customer Support" - } + "id": 13, + "firstName": "First Name (13)", + "lastName": "Last Name (13)", + "birthdate": "1955-06-30T00:00:00", + "department": { + "id": 1, + "name": "IT", + "employees": null + } + }, + ... ], "aggregate": null, "sort": [ @@ -586,23 +596,10 @@ The follwings are some exmaples. }, "filters": [ { - "field": "ID", + "field": "Department.Name", "operator": "=", - "value": "1", - "or": [ - { - "field": "ID", - "operator": "=", - "value": "5", - "or": null - }, - { - "field": "ID", - "operator": "=", - "value": "12", - "or": null - } - ] + "value": "IT", + "or": null } ], "columns": [ @@ -638,63 +635,511 @@ The follwings are some exmaples. } ], "pagination": { - "count": 1, + "count": 9, "pageSize": 10, "pageStart": 0, - "pageEnd": 0, + "pageEnd": 8, "pageIndex": 0, "hasPreviousPage": false, "hasNextPage": false, - "lastPageIndex": 0, + "lastPageIndex": 8, "dataStart": 1, - "dataEnd": 3 + "dataEnd": 20 }, - "beforeLoadingData": "2022-07-17T09:15:15.9393452Z", - "afterLoadingData": "2022-07-17T09:15:15.9884659Z" + "beforeLoadingData": "2022-07-19T12:19:17.04074Z", + "afterLoadingData": "2022-07-19T12:19:17.1363004Z" } ``` - -### Grid Column exclusion -A column can be excluded in the generated SQL query using the [`GridColumn`](/reference/#gridcolumn) object when visible is set to false, if the column comes from a table join, the join will be omitted - +#### Filtering subitems and ORing === "C#" ``` C# - [HttpPost("columns")] - public async Task Columns() - { - var db = new DB(); + [HttpPost("filters-subitems-and-or")] + public async Task Filters_SubItems_AndOr() + { + var db = new DB(); - var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; - var shiftGrid = - await db - .Employees - .Select(x => new - { - x.ID, - x.FirstName, - x.LastName, - x.Birthdate, - Department = x.Department.Name - }) - .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig - { - Columns = new List + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + x.Department + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter { - new GridColumn - { - Field = "FirstName", - Visible = false - }, - new GridColumn + Field = "Department.Name", + Operator = GridFilterOperator.Equals, + Value = "IT", + OR = new List { - Field = "Department", - Visible = false + new GridFilter { + Field = nameof(Employee.FirstName), + Operator = GridFilterOperator.EndsWith, + Value = "7)", + } } } - }); - return Ok(shiftGrid); + } + }); + + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [d].[ID], [d].[Name] + FROM [Employees] AS [e] + LEFT JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[ID] + WHERE ([d].[Name] = N''IT'') OR ([e].[FirstName] LIKE N''%7)'') + ORDER BY [e].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 } + ], + "filters": [ + { + "field": "Department.Name", + "operator": "=", + "value":"IT", + "or": [ + { + "field": "FirstName", + "operator": "EndsWith", + "value":"7)" + } + ] + } + ], + "columns": [], + "pagination": { + "pageSize": 10 + } + } + ``` +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 233, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "department": { + "id": 1, + "name": "IT", + "employees": null + } + }, + ... + { + "id": 17, + "firstName": "First Name (17)", + "lastName": "Last Name (17)", + "birthdate": "1955-08-29T00:00:00", + "department": { + "id": 5, + "name": "Marketing", + "employees": null + } + }, + ... + ], + "aggregate": null, + "sort": [...], + "stableSort": {...}, + "filters": [...], + "columns": [...], + "pagination": {...}, + "beforeLoadingData": "2022-07-19T14:03:42.1161452Z", + "afterLoadingData": "2022-07-19T14:03:42.2312512Z" + } + ``` +=== "Response (Full)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 233, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "department": { + "id": 1, + "name": "IT", + "employees": null + } + }, + ... + { + "id": 17, + "firstName": "First Name (17)", + "lastName": "Last Name (17)", + "birthdate": "1955-08-29T00:00:00", + "department": { + "id": 5, + "name": "Marketing", + "employees": null + } + }, + ... + ], + "aggregate": null, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [ + { + "field": "Department.Name", + "operator": "=", + "value": "IT", + "or": [ + { + "field": "FirstName", + "operator": "EndsWith", + "value": "7)", + "or": null + } + ] + } + ], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": true, + "order": 1 + }, + { + "headerText": "LastName", + "field": "LastName", + "visible": true, + "order": 2 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 3 + }, + { + "headerText": "Department", + "field": "Department", + "visible": true, + "order": 4 + } + ], + "pagination": { + "count": 12, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 9, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": true, + "lastPageIndex": 11, + "dataStart": 1, + "dataEnd": 20 + }, + "beforeLoadingData": "2022-07-19T14:03:42.1161452Z", + "afterLoadingData": "2022-07-19T14:03:42.2312512Z" + } + ``` +#### Filtering Navigated Items and Subitems Aggregates +=== "C#" + ``` C# + [HttpPost("filters-navigated-items-and-subitems-aggregates")] + public async Task Filters_NavigatedItems_AndSubItemsAggregates() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Departments + .Select(x => new + { + x.ID, + x.Name, + Employees = x.Employees.Select(y => new + { + EmployeeID = y.ID * 10 + }) + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Filters = new List { + new GridFilter + { + Field = "Employees.Min(EmployeeID)", + Operator = GridFilterOperator.Equals, + Value = 10, + }, + new GridFilter + { + Field = "Name", + Operator = GridFilterOperator.Equals, + Value = "IT", + }, + new GridFilter + { + Field = "Employees.Max(EmployeeID)", + Operator = GridFilterOperator.Equals, + Value = 9970, + } + + } + }); + + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [d].[ID], [d].[Name], [e1].[ID] * CAST(10 AS bigint), [e1].[ID] + FROM [Departments] AS [d] + LEFT JOIN [Employees] AS [e1] ON [d].[ID] = [e1].[DepartmentId] + WHERE ((( + SELECT MIN([e].[ID] * CAST(10 AS bigint)) + FROM [Employees] AS [e] + WHERE [d].[ID] = [e].[DepartmentId]) = CAST(10 AS bigint)) AND ([d].[Name] = N'IT')) AND (( + SELECT MAX([e0].[ID] * CAST(10 AS bigint)) + FROM [Employees] AS [e0] + WHERE [d].[ID] = [e0].[DepartmentId]) = CAST(9970 AS bigint)) + ORDER BY [d].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "filters": [ + { + "field": "Employees.Min(EmployeeID)", + "operator": "=", + "value":10 + }, + { + "field": "Name", + "operator": "=", + "value":"IT" + }, + { + "field": "Employees.Max(EmployeeID)", + "operator": "=", + "value":9970 + } + ], + "columns": [], + "pagination": { + "pageSize": 10 + } + } + ``` +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1, + "data": [ + { + "id": 1, + "name": "IT", + "employees": [ + { + "employeeID": 10 + }, + ... + { + "employeeID": 9970 + } + ] + } + ], + "aggregate": null, + "sort": [...], + "stableSort": {...}, + "filters": [...], + "columns": [...], + "pagination": {...}, + "beforeLoadingData": "2022-07-19T15:24:52.7590163Z", + "afterLoadingData": "2022-07-19T15:24:52.779971Z" + } + ``` +=== "Response (Full)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1, + "data": [ + { + "id": 1, + "name": "IT", + "employees": [ + { + "employeeID": 10 + }, + ... + { + "employeeID": 9970 + } + ] + } + ], + "aggregate": null, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [ + { + "field": "Employees.Min(EmployeeID)", + "operator": "=", + "value": 10, + "or": null + }, + { + "field": "Name", + "operator": "=", + "value": "IT", + "or": null + }, + { + "field": "Employees.Max(EmployeeID)", + "operator": "=", + "value": 9970, + "or": null + } + ], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": "Name", + "field": "Name", + "visible": true, + "order": 1 + }, + { + "headerText": "Employees", + "field": "Employees", + "visible": true, + "order": 2 + } + ], + "pagination": { + "count": 1, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 0, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": false, + "lastPageIndex": 0, + "dataStart": 1, + "dataEnd": 1 + }, + "beforeLoadingData": "2022-07-19T15:24:52.7590163Z", + "afterLoadingData": "2022-07-19T15:24:52.779971Z" + } + ``` + +### Grid Column Exclusion +A column can be excluded in the generated SQL query using the [`GridColumn`](/reference/#gridcolumn) object when visible is set to false, if the column comes from a table join, the join will be omitted + +=== "C#" + ``` C# + [HttpPost("columns")] + public async Task Columns() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new + { + x.ID, + x.FirstName, + x.LastName, + x.Birthdate, + Department = x.Department.Name + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = "FirstName", + Visible = false + }, + new GridColumn + { + Field = "Department", + Visible = false + } + } + }); + return Ok(shiftGrid); + } ``` === "SQL" ``` SQL From 520c17b4630ebeea55be0c7e47d620f6b2923b18 Mon Sep 17 00:00:00 2001 From: Sarmad Date: Wed, 20 Jul 2022 00:32:25 +0300 Subject: [PATCH 10/10] Column Order examples --- PlayGround/Controllers/Default.cs | 73 +++++- ShiftGrid.Core/docs/examples.md | 417 +++++++++++++++++++++++++++++- 2 files changed, 488 insertions(+), 2 deletions(-) diff --git a/PlayGround/Controllers/Default.cs b/PlayGround/Controllers/Default.cs index f090de3..2fb4a21 100644 --- a/PlayGround/Controllers/Default.cs +++ b/PlayGround/Controllers/Default.cs @@ -328,7 +328,77 @@ await db }); return Ok(shiftGrid); } - + class OrderModel + { + public long ID { get; set; } + public string FirstName { get; set; } + [GridColumnAttribute(Order = 1)] + public string LastName { get; set; } + public DateTime? Birthdate { get; set; } + [GridColumnAttribute(Order = 0)] + public long? DepartmentId { get; set; } + + public virtual Department? Department { get; set; } + + } + [HttpPost("order-by-attributes")] + public async Task Order_ByAttributes() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new OrderModel + { + ID = x.ID, + FirstName = x.FirstName, + LastName = x.LastName, + Birthdate = x.Birthdate, + DepartmentId = x.DepartmentId + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + + }); + return Ok(shiftGrid); + } + [HttpPost("order-overwrite-attribute-with-existing-order")] + public async Task Order_OverwriteAttribute_WithExistingOrder() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new OrderModel + { + ID = x.ID, + FirstName = x.FirstName, + LastName = x.LastName, + Birthdate = x.Birthdate, + DepartmentId = x.DepartmentId + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = nameof(OrderModel.ID), // 0 is already assigned to DepartmentId by another attribute + Order = 0 + } + } + + }); + return Ok(shiftGrid); + } + + [HttpPost("filters-equals")] public async Task Filters_Equals() { @@ -560,6 +630,7 @@ await db return Ok(shiftGrid); } + [FileHelpers.DelimitedRecord(",")] public class EmployeeCSV { diff --git a/ShiftGrid.Core/docs/examples.md b/ShiftGrid.Core/docs/examples.md index c9a6c89..595954d 100644 --- a/ShiftGrid.Core/docs/examples.md +++ b/ShiftGrid.Core/docs/examples.md @@ -1306,7 +1306,7 @@ A column can be excluded in the generated SQL query using the [`GridColumn`](/re } ``` ???+ warning - the `select` method must exist for the exclusion to be done successfully + the `Select` method must exist for the exclusion to be done successfully ???+ info if the excluded column is the same as the one used for sorting its value will be 0 not null, in our exampe if ID is excluded it will be 0. #### Excluding Collections @@ -2257,3 +2257,418 @@ Two identical column, one is a normal column and the other one is inside the col "afterLoadingData": "2022-07-19T11:07:58.2177103Z" } ``` + +### Grid Column Ordering +#### Ordering by Attribute +The grid columns can be ordered using `GridColumnAttribute` +=== "C#" + ``` C# + [HttpPost("order-by-attributes")] + public async Task Order_ByAttributes() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new OrderModel + { + ID = x.ID, + FirstName = x.FirstName, + LastName = x.LastName, + Birthdate = x.Birthdate, + DepartmentId = x.DepartmentId + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + {}); + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [e].[DepartmentId] + FROM [Employees] AS [e] + ORDER BY [e].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "columns": [ + { + "field":"DepartmentId", + "order":0 + }, + { + "field":"LastName", + "order":1 + } + ], + "pagination": { + "pageSize": 10 + }, + "filters": [ + ] + } + ``` +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1000, + "data": [...], + "aggregate": null, + "sort": [...], + "stableSort": {...}, + "filters": [], + "columns": [ + { + "headerText": null, + "field": "DepartmentId", + "visible": true, + "order": 0 + }, + { + "headerText": null, + "field": "LastName", + "visible": true, + "order": 1 + }, + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 2 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": true, + "order": 3 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 4 + }, + { + "headerText": "Department", + "field": "Department", + "visible": true, + "order": 5 + } + ], + "pagination": {...}, + "beforeLoadingData": "2022-07-17T13:35:54.5310457Z", + "afterLoadingData": "2022-07-17T13:35:54.5351803Z" + } + ``` +=== "Response (Full)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1000, + "data": [ + { + "id": 1, + "firstName": null, + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "department": null + }, + ... + ], + "aggregate": null, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [], + "columns": [ + { + "headerText": null, + "field": "DepartmentId", + "visible": true, + "order": 0 + }, + { + "headerText": null, + "field": "LastName", + "visible": true, + "order": 1 + }, + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 2 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": true, + "order": 3 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 4 + }, + { + "headerText": "Department", + "field": "Department", + "visible": true, + "order": 5 + } + ], + "pagination": { + "count": 50, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 9, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": true, + "lastPageIndex": 49, + "dataStart": 1, + "dataEnd": 20 + }, + "beforeLoadingData": "2022-07-19T19:26:06.6196532Z", + "afterLoadingData": "2022-07-19T19:26:06.6226608Z" + } + ``` +???+ note + the follwing mock model is used to appy the `GridColumnAttribute` + ``` C# + class OrderModel + { + public long ID { get; set; } + public string FirstName { get; set; } + [GridColumnAttribute(Order = 1)] + public string LastName { get; set; } + public DateTime? Birthdate { get; set; } + [GridColumnAttribute(Order = 0)] + public long? DepartmentId { get; set; } + + public virtual Department? Department { get; set; } + + } + ``` +#### Overwriting Attribute with existing Order +The `GridColumnAttribute` can be overwritten using the `GridColumn`'s `Order` +=== "C#" + ``` C# + [HttpPost("order-overwrite-attribute-with-existing-order")] + public async Task Order_OverwriteAttribute_WithExistingOrder() + { + var db = new DB(); + + var DbF = Microsoft.EntityFrameworkCore.EF.Functions; + + var shiftGrid = + await db + .Employees + .Select(x => new OrderModel + { + ID = x.ID, + FirstName = x.FirstName, + LastName = x.LastName, + Birthdate = x.Birthdate, + DepartmentId = x.DepartmentId + }) + .ToShiftGridAsync("ID", SortDirection.Ascending, new GridConfig + { + Columns = new List + { + new GridColumn + { + Field = nameof(OrderModel.ID), // 0 is already assigned to DepartmentId by another attribute + Order = 0 + } + } + + }); + return Ok(shiftGrid); + } + ``` +=== "SQL" + ``` SQL + SELECT [e].[ID], [e].[FirstName], [e].[LastName], [e].[Birthdate], [e].[DepartmentId] + FROM [Employees] AS [e] + ORDER BY [e].[ID] + ``` +=== "Request" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 5, + "sort": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "columns": [ + { + "field": "ID", + "sortDirection": 0 + } + ], + "pagination": { + "pageSize": 10 + }, + "filters": [ + ] + } + ``` +=== "Response (Omitted)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1000, + "data": [...], + "aggregate": null, + "sort": [], + "stableSort": {...}, + "filters": [], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": null, + "field": "LastName", + "visible": true, + "order": 1 + }, + { + "headerText": null, + "field": "DepartmentId", + "visible": true, + "order": 1 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": true, + "order": 2 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 3 + }, + { + "headerText": "Department", + "field": "Department", + "visible": true, + "order": 4 + } + ], + "pagination": {...}, + "beforeLoadingData": "2022-07-19T19:48:15.1717737Z", + "afterLoadingData": "2022-07-19T19:48:15.1737214Z" + } + ``` +=== "Response (Full)" + ``` JSON + { + "dataPageIndex": 0, + "dataPageSize": 20, + "dataCount": 1000, + "data": [ + { + "id": 1, + "firstName": "First Name (1)", + "lastName": "Last Name (1)", + "birthdate": "1955-01-01T00:00:00", + "departmentId": 1, + "department": null + }, + ... + ], + "aggregate": null, + "sort": [], + "stableSort": { + "field": "ID", + "sortDirection": 0 + }, + "filters": [], + "columns": [ + { + "headerText": "ID", + "field": "ID", + "visible": true, + "order": 0 + }, + { + "headerText": null, + "field": "LastName", + "visible": true, + "order": 1 + }, + { + "headerText": null, + "field": "DepartmentId", + "visible": true, + "order": 1 + }, + { + "headerText": "FirstName", + "field": "FirstName", + "visible": true, + "order": 2 + }, + { + "headerText": "Birthdate", + "field": "Birthdate", + "visible": true, + "order": 3 + }, + { + "headerText": "Department", + "field": "Department", + "visible": true, + "order": 4 + } + ], + "pagination": { + "count": 50, + "pageSize": 10, + "pageStart": 0, + "pageEnd": 9, + "pageIndex": 0, + "hasPreviousPage": false, + "hasNextPage": true, + "lastPageIndex": 49, + "dataStart": 1, + "dataEnd": 20 + }, + "beforeLoadingData": "2022-07-19T19:48:15.1717737Z", + "afterLoadingData": "2022-07-19T19:48:15.1737214Z" + } + ```