This commit is contained in:
2020-02-11 22:55:58 +00:00
parent aa0c73d415
commit 9625baa8da
10 changed files with 188 additions and 193 deletions

View File

@@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace AyaNova.Api.ControllerHelpers
{
public class ApiDataListResponse
{
public object Data { get; }
public long TotalRecordCount { get; }
public object Columns {get;}
public ApiDataListResponse(object returnItems, long totalRecordCount, Newtonsoft.Json.Linq.JArray columns)
{
Data = returnItems;
TotalRecordCount = totalRecordCount;
Columns = columns;
}
}//eoc
}//eons

View File

@@ -1,38 +0,0 @@
using System.Collections.Generic;
namespace AyaNova.Api.ControllerHelpers
{
public class ApiOkWithPagingResponse<T>
{
public object Data { get; }
public object Paging { get; }
public ApiOkWithPagingResponse(ApiPagedResponse<T> pr)
{
Data = pr.items;
Paging = pr.PageLinks;
}
}//eoc
public class ApiOkWithPagingResponse
{
public object Data { get; }
public object Paging { get; }
public object Columns {get;}
public ApiOkWithPagingResponse(ApiPagedResponse pr)
{
Data = pr.items;
Paging = pr.PageLinks;
Columns = pr.Columns;
}
}//eoc
}//eons

View File

@@ -1,42 +1,42 @@
using System.Collections.Generic;
using AyaNova.Models;
// using System.Collections.Generic;
// using AyaNova.Models;
namespace AyaNova.Api.ControllerHelpers
{
// namespace AyaNova.Api.ControllerHelpers
// {
public class ApiPagedResponse<T>
{
// // public class ApiPagedResponse<T>
// // {
public T[] items { get; }
public object PageLinks { get; }
public object Columns { get; }
// // public T[] items { get; }
// // public object PageLinks { get; }
// // public object Columns { get; }
public ApiPagedResponse(T[] returnItems, object pageLinks, object columns = null)
{
items = returnItems;
PageLinks = pageLinks;
Columns = Columns;
// // public ApiPagedResponse(T[] returnItems, object pageLinks, object columns = null)
// // {
// // items = returnItems;
// // PageLinks = pageLinks;
// // Columns = Columns;
}
}//eoc
// // }
// // }//eoc
public class ApiPagedResponse
{
// public class ApiPagedResponse
// {
public object items { get; }
public object PageLinks { get; }
public Newtonsoft.Json.Linq.JArray Columns { get; }
// public object items { get; }
// public object PageLinks { get; }
// public Newtonsoft.Json.Linq.JArray Columns { get; }
public ApiPagedResponse(object returnItems, object pageLinks, Newtonsoft.Json.Linq.JArray columns)
{
items = returnItems;
PageLinks = pageLinks;
Columns = columns;
// public ApiPagedResponse(object returnItems, object pageLinks, Newtonsoft.Json.Linq.JArray columns)
// {
// items = returnItems;
// PageLinks = pageLinks;
// Columns = columns;
}
}//eoc
// }
// }//eoc
}//eons
// }//eons

View File

@@ -10,25 +10,31 @@ namespace AyaNova.Api.ControllerHelpers
public const int DefaultOffset = 0;
public const int DefaultLimit = 25;
[FromQuery]
[FromBody]
[Range(0, int.MaxValue)]
public int? Offset { get; set; }
[FromQuery]
[FromBody]
[Range(1, MaxPageSize, ErrorMessage = "Limit must be greater than 0 and less than 1000.")]
public int? Limit { get; set; }
//Data filter id to use with this list query
//0 or less means no filter
[FromQuery]
public long DataFilterId { get; set; }
// //Data filter id to use with this list query
// //0 or less means no filter
// [FromBody]
// public long DataFilterId { get; set; }
[FromQuery]
[FromBody]
public bool Mini { get; set; }
[FromQuery, Required]
[FromBody, Required]
public string DataListKey { get; set; }
[FromBody]
public string FilterJson { get; set; }
[FromBody]
public string SortJson { get; set; }
}

View File

@@ -1,89 +1,89 @@
using System;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
// using System;
// using Microsoft.AspNetCore.Routing;
// using Microsoft.AspNetCore.Mvc;
// using Newtonsoft.Json;
namespace AyaNova.Api.ControllerHelpers
{
// namespace AyaNova.Api.ControllerHelpers
// {
public class PaginationLinkBuilder
{ //adapted from //https://www.jerriepelser.com/blog/paging-in-aspnet-webapi-pagination-links/
public Uri FirstPage { get; private set; }
public Uri LastPage { get; private set; }
public Uri NextPage { get; private set; }
public Uri PreviousPage { get; private set; }
public ListOptions PagingOptions { get; }
public long TotalRecordCount { get; }
// public class PaginationLinkBuilder
// { //adapted from //https://www.jerriepelser.com/blog/paging-in-aspnet-webapi-pagination-links/
// public Uri FirstPage { get; private set; }
// public Uri LastPage { get; private set; }
// public Uri NextPage { get; private set; }
// public Uri PreviousPage { get; private set; }
// public ListOptions PagingOptions { get; }
// public long TotalRecordCount { get; }
public PaginationLinkBuilder(IUrlHelper urlHelper, string routeName, object routeValues, ListOptions pagingOptions, long totalRecordCount)
{
PagingOptions = pagingOptions;
TotalRecordCount = totalRecordCount;
// public PaginationLinkBuilder(IUrlHelper urlHelper, string routeName, object routeValues, ListOptions pagingOptions, long totalRecordCount)
// {
// PagingOptions = pagingOptions;
// TotalRecordCount = totalRecordCount;
// Determine total number of pages
var pageCount = totalRecordCount > 0
? (int)Math.Ceiling(totalRecordCount / (double)pagingOptions.Limit)
: 0;
// // Determine total number of pages
// var pageCount = totalRecordCount > 0
// ? (int)Math.Ceiling(totalRecordCount / (double)pagingOptions.Limit)
// : 0;
// Create page links
// // Create page links
FirstPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues)
{
{"pageNo", 1},
{"pageSize", pagingOptions.Limit}
}));
// FirstPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues)
// {
// {"pageNo", 1},
// {"pageSize", pagingOptions.Limit}
// }));
LastPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues)
{
{"pageNo", pageCount},
{"pageSize", pagingOptions.Limit}
}));
// LastPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues)
// {
// {"pageNo", pageCount},
// {"pageSize", pagingOptions.Limit}
// }));
if (pagingOptions.Offset > 1)
{
PreviousPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues)
{
{"pageNo", pagingOptions.Offset - 1},
{"pageSize", pagingOptions.Limit}
}));
}
// if (pagingOptions.Offset > 1)
// {
// PreviousPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues)
// {
// {"pageNo", pagingOptions.Offset - 1},
// {"pageSize", pagingOptions.Limit}
// }));
// }
if (pagingOptions.Offset < pageCount)
{
NextPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues)
{
{"pageNo", pagingOptions.Offset + 1},
{"pageSize", pagingOptions.Limit}
}));
}
// if (pagingOptions.Offset < pageCount)
// {
// NextPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues)
// {
// {"pageNo", pagingOptions.Offset + 1},
// {"pageSize", pagingOptions.Limit}
// }));
// }
}
// }
/// <summary>
/// Return paging data suitable for API return
/// </summary>
/// <returns></returns>
public Object PagingLinksObject()
{
return new
{
Count = TotalRecordCount,
Offset = PagingOptions.Offset,
Limit = PagingOptions.Limit,
First = FirstPage,
Previous = PreviousPage,
Next = NextPage,
Last = LastPage
};
}
// /// <summary>
// /// Return paging data suitable for API return
// /// </summary>
// /// <returns></returns>
// public Object PagingLinksObject()
// {
// return new
// {
// Count = TotalRecordCount,
// Offset = PagingOptions.Offset,
// Limit = PagingOptions.Limit,
// First = FirstPage,
// Previous = PreviousPage,
// Next = NextPage,
// Last = LastPage
// };
// }
}
// }
}
// }

View File

@@ -48,8 +48,8 @@ namespace AyaNova.Api.Controllers
/// </summary>
/// <param name="listOptions">List key, Paging, filtering and sorting options</param>
/// <returns>Collection with paging data</returns>
[HttpGet("List", Name = nameof(List))]
public async Task<IActionResult> List([FromQuery] ListOptions listOptions)
[HttpPost("List", Name = nameof(List))]
public async Task<IActionResult> List([FromBody] ListOptions listOptions)
{
if (serverState.IsClosed)
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
@@ -62,8 +62,8 @@ namespace AyaNova.Api.Controllers
try
{
ApiPagedResponse pr = await DataListFetcher.GetResponseAsync(listOptions.DataListKey, ct, Url, nameof(List), listOptions, UserId, UserRoles);
return Ok(new ApiOkWithPagingResponse(pr));
ApiDataListResponse r = await DataListFetcher.GetResponseAsync(listOptions.DataListKey, ct, Url, nameof(List), listOptions, UserId, UserRoles);
return Ok(r);
}
catch (System.UnauthorizedAccessException)
{

View File

@@ -13,7 +13,7 @@ namespace AyaNova.DataList
{
internal static class DataListFetcher
{
internal static async Task<ApiPagedResponse> GetResponseAsync(string DataListKey, AyContext ct, IUrlHelper Url,
internal static async Task<ApiDataListResponse> GetResponseAsync(string DataListKey, AyContext ct, IUrlHelper Url,
string routeName, ListOptions listOptions, long UserId, AuthorizationRoles UserRoles)
{
@@ -78,15 +78,19 @@ namespace AyaNova.DataList
DataListFilter TheFilter = null;
var qWhere = string.Empty;
var qOrderBy = string.Empty;
if (listOptions.DataFilterId > 0)
if (!string.IsNullOrWhiteSpace(listOptions.FilterJson))
{
TheFilter = await ct.DataListFilter.FirstOrDefaultAsync(x => x.Id == listOptions.DataFilterId);
//WHERE CLAUSE - FILTER
qWhere = DataListSqlFilterCriteriaBuilder.DataFilterToSQLCriteria(DataList.FieldDefinitions, TheFilter, DataList.FieldDefinitions, UserId);
qWhere = DataListSqlFilterCriteriaBuilder.DataFilterToSQLCriteria(DataList.FieldDefinitions, listOptions.FilterJson, DataList.FieldDefinitions, UserId);
}
if (!string.IsNullOrWhiteSpace(listOptions.SortJson))
{
//ORDER BY CLAUSE - SORT
//BUILD ORDER BY
qOrderBy = DataListSqlFilterOrderByBuilder.DataFilterToSQLOrderBy(DataList.FieldDefinitions, TheFilter);
}else{
qOrderBy = DataListSqlFilterOrderByBuilder.DataFilterToSQLOrderBy(DataList.FieldDefinitions, listOptions.SortJson);
}
else
{
//BUILD DEFAULT ORDER BY IF POSSIBLE
qOrderBy = DataListSqlFilterOrderByBuilder.DataFilterToSQLOrderBy(DataList.FieldDefinitions, null);
}
@@ -180,38 +184,41 @@ namespace AyaNova.DataList
}
}
//RES.PAGING.COUNT is all I need so the rest is moot, particularly since it's a post method now to get a datalist not a GET with query parameters
//below commented stuff can go once it tests
//BUILD THE PAGING LINKS PORTION
//var pageLinks = new PaginationLinkBuilder(Url, routeName, null, listOptions, totalRecordCount).PagingLinksObject();
//http://localhost:7575/api/v8/DataList/List?Offset=2&Limit=3&DataFilterId=2&Mini=true&DataListKey=TestWidgetDataList
object routeValues = null;
//no data filter?
if (listOptions.DataFilterId == 0)
{
if (listOptions.Mini)
{
routeValues = new { DataListKey = DataListKey, Mini = listOptions.Mini };
}
else
{
routeValues = new { DataListKey = DataListKey };
}
}
else
{
if (listOptions.Mini)
{
routeValues = new { DataListKey = DataListKey, DataFilterId = listOptions.DataFilterId, Mini = listOptions.Mini };
}
else
{
routeValues = new { DataListKey = DataListKey, DataFilterId = listOptions.DataFilterId };
}
}
// object routeValues = null;
// //no data filter?
// if (listOptions.DataFilterId == 0)
// {
// if (listOptions.Mini)
// {
// routeValues = new { DataListKey = DataListKey, Mini = listOptions.Mini };
// }
// else
// {
// routeValues = new { DataListKey = DataListKey };
// }
// }
// else
// {
// if (listOptions.Mini)
// {
// routeValues = new { DataListKey = DataListKey, DataFilterId = listOptions.DataFilterId, Mini = listOptions.Mini };
// }
// else
// {
// routeValues = new { DataListKey = DataListKey, DataFilterId = listOptions.DataFilterId };
// }
// }
var pageLinks = new PaginationLinkBuilder(Url, routeName, routeValues, listOptions, totalRecordCount).PagingLinksObject();
// var pageLinks = new PaginationLinkBuilder(Url, routeName, routeValues, listOptions, totalRecordCount).PagingLinksObject();
//BUILD THE COLUMNS RETURN PROPERTY JSON FRAGMENT
Newtonsoft.Json.Linq.JArray ColumnsJSON = null;
@@ -225,8 +232,8 @@ namespace AyaNova.DataList
}
ApiPagedResponse pr = new ApiPagedResponse(rows, pageLinks, ColumnsJSON);
return pr;
return new ApiDataListResponse(rows, totalRecordCount, ColumnsJSON);
}

View File

@@ -11,10 +11,10 @@ namespace AyaNova.DataList
{
public static class DataListSqlFilterCriteriaBuilder
{
public static string DataFilterToSQLCriteria(List<AyaDataListFieldDefinition> objectFieldsList, AyaNova.Models.DataListFilter dataFilter, List<AyaDataListFieldDefinition> objectFields, long userId)
public static string DataFilterToSQLCriteria(List<AyaDataListFieldDefinition> objectFieldsList, string filterJson, List<AyaDataListFieldDefinition> objectFields, long userId)
{
if (string.IsNullOrWhiteSpace(dataFilter.Filter))
if (string.IsNullOrWhiteSpace(filterJson))
{
return "";
}
@@ -22,7 +22,7 @@ namespace AyaNova.DataList
StringBuilder sb = new StringBuilder();
//iterate the datafilter and concatenate a sql query from it
var FilterArray = JArray.Parse(dataFilter.Filter);
var FilterArray = JArray.Parse(filterJson);
for (int i = 0; i < FilterArray.Count; i++)
{

View File

@@ -12,10 +12,10 @@ namespace AyaNova.DataList
// public static string DefaultPickListOrderBy => "ORDER BY NAME ASC";
public static string DataFilterToSQLOrderBy(List<AyaDataListFieldDefinition> objectFieldsList, AyaNova.Models.DataListFilter dataFilter)
public static string DataFilterToSQLOrderBy(List<AyaDataListFieldDefinition> objectFieldsList, string SortJson)
{
if (dataFilter == null || string.IsNullOrWhiteSpace(dataFilter.Sort))
if ( string.IsNullOrWhiteSpace(SortJson))
{
//sort by default field descending which should in theory always be the id column of the main object in the list
//which should return the results to user with most recent records at the top if no sort order was specified
@@ -33,7 +33,7 @@ namespace AyaNova.DataList
StringBuilder sb = new StringBuilder();
//iterate the datafilter and concatenate a sql query from it
var SortArray = JArray.Parse(dataFilter.Sort);
var SortArray = JArray.Parse(SortJson);
for (int i = 0; i < SortArray.Count; i++)
{

View File

@@ -220,16 +220,12 @@ namespace AyaNova.Biz
var DataList = DataListFactory.GetAyaDataList(inObj.ListKey);
// List<AyaDataListFieldDefinition> FieldList = null;
//if (!AyaFormFieldDefinitions.IsValidFormFieldDefinitionKey(inObj.ListKey))
if (DataList == null)
{
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "ListKey", $"ListKey \"{inObj.ListKey}\" DataListKey is not valid");
}
// else
// {
// FieldList = AyaDataListFieldDefinition.AyaObjectFields(inObj.ListKey);
// }
if (inObj.ListKey.Length > 255)
@@ -284,6 +280,8 @@ namespace AyaNova.Biz
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Filter", $"Filter array item {i}, object is missing or is empty the required \"value\" property ");
else
{
//check if the value is present, not what it is exactly, just that it's present
//value also could contain relative date tokens, not that it checks them anyway but just noting it here
if (filterItem["value"].Type == JTokenType.String && string.IsNullOrWhiteSpace(filterItem["value"].Value<string>()))
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Filter", $"Filter array item {i}, object is missing or is empty the required \"value\" property ");