This commit is contained in:
2018-12-13 00:17:36 +00:00
parent 4060d8900f
commit a0e8192352
6 changed files with 325 additions and 45 deletions

View File

@@ -5,17 +5,12 @@ Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNTQ0NTU5NzAwIiwiZXhwIjoi
## IMMEDIATE ITEMS
User - implement filter on usertype so we have at least one enum filter, also these filters are going to be used internally by a lot of code
to fill pick lists and such in the UI so they must support most things I would need to filter by inluding enums.
- No need for other enum filters just yet, add them as required so there's no YAGNI happening.
Widget and user picklist, modify to use filter and sort criteria, remove the startswith built in filter
- Fix up the old tests for picklists and replace with new test using filter ID
- Don't forget to test with no filter ID to ensure still works as normal (default picklist should sort by alpha, need extra default method for sql query)
User
- Create one filter and sort test that can be adapted for all other objects so we know each object has one basic test for it's filter and sort code
- Probably just filter by name and sort by active to be most universal
ENUM
- Need route to get enum values and lt by providing a lowercase name of the enum (used for building filter UI for enum types)
- Client needs to pick enum value adn display localized

View File

@@ -133,7 +133,37 @@ namespace AyaNova.Api.Controllers
/// <summary>
// /// <summary>
// /// Get widget pick list
// ///
// /// Required roles: Any
// ///
// /// This list supports querying the Name property
// /// include a "q" parameter for string to search for
// /// use % for wildcards.
// ///
// /// e.g. q=%Jones%
// ///
// /// Query is case insensitive
// /// </summary>
// /// <returns>Paged id/name collection of widgets with paging data</returns>
// [HttpGet("PickList", Name = nameof(WidgetPickList))]
// public async Task<IActionResult> WidgetPickList([FromQuery] string q, [FromQuery] PagingOptions pagingOptions)
// {
// if (serverState.IsClosed)
// return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
// if (!ModelState.IsValid)
// return BadRequest(new ApiErrorResponse(ModelState));
// //Instantiate the business object handler
// WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
// ApiPagedResponse<NameIdItem> pr = await biz.GetPickListAsync(Url, nameof(WidgetPickList), pagingOptions, q);
// return Ok(new ApiOkWithPagingResponse<NameIdItem>(pr));
// }
/// <summary>
/// Get widget pick list
///
/// Required roles: Any
@@ -148,7 +178,7 @@ namespace AyaNova.Api.Controllers
/// </summary>
/// <returns>Paged id/name collection of widgets with paging data</returns>
[HttpGet("PickList", Name = nameof(WidgetPickList))]
public async Task<IActionResult> WidgetPickList([FromQuery] string q, [FromQuery] PagingOptions pagingOptions)
public async Task<IActionResult> WidgetPickList([FromQuery] PagingOptions pagingOptions)
{
if (serverState.IsClosed)
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
@@ -159,7 +189,7 @@ namespace AyaNova.Api.Controllers
//Instantiate the business object handler
WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
ApiPagedResponse<NameIdItem> pr = await biz.GetPickListAsync(Url, nameof(WidgetPickList), pagingOptions, q);
ApiPagedResponse<NameIdItem> pr = await biz.GetPickListAsync(Url, nameof(WidgetPickList), pagingOptions);
return Ok(new ApiOkWithPagingResponse<NameIdItem>(pr));
}

View File

@@ -0,0 +1,109 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.JsonPatch;
using EnumsNET;
using AyaNova.Util;
using AyaNova.Api.ControllerHelpers;
using AyaNova.Biz;
using AyaNova.Models;
using System.Collections.Generic;
using System.Linq;
namespace AyaNova.Biz
{
internal static class PickListFetcher
{
internal static PickListResult GetPickList(AyContext ct, long userId, PagingOptions pagingOptions, string tableName)
{
List<NameIdItem> listItems = new List<NameIdItem>();
using (var cm = ct.Database.GetDbConnection().CreateCommand())
{
ct.Database.OpenConnection();
//BUILD THE QUERY
//base query
var q = $"SELECT id, name FROM {tableName} ";
//GET THE FILTER / SORT
if (pagingOptions.DataFilterId > 0)
{
var TheFilter = ct.DataFilter.FirstOrDefault(x => x.Id == pagingOptions.DataFilterId);
//BUILD WHERE AND APPEND IT
q = q + FilterSqlCriteriaBuilder.DataFilterToSQLCriteria(TheFilter, WidgetBiz.FilterOptions(), userId);
//BUILD ORDER BY AND APPEND IT
q = q + FilterSqlOrderByBuilder.DataFilterToSQLOrderBy(TheFilter);
}
else
{
//GET DEFAULT ORDER BY
q = q + FilterSqlOrderByBuilder.DefaultOrderBy();
}
cm.CommandText = q;
using (var dr = cm.ExecuteReader())
{
while (dr.Read())
{
listItems.Add(new NameIdItem() { Id = dr.GetInt64(0), Name = dr.GetString(1) });
}
}
}
PickListResult ret = new PickListResult();
ret.Items = listItems.ToArray();
ret.TotalRecordCount = 9999;
return ret;
}
// //Returns existance status of object type and id specified in database
// internal static string Name(AyaType aytype, long id, System.Data.Common.DbCommand cmd)
// {
// string TABLE = string.Empty;
// string COLUMN = "name";
// switch (aytype)
// {
// case AyaType.User:
// TABLE = "auser";
// break;
// case AyaType.Widget:
// TABLE = "awidget";
// break;
// case AyaType.FileAttachment:
// TABLE = "afileattachment";
// COLUMN = "displayfilename";
// break;
// case AyaType.DataFilter:
// TABLE = "adatafilter";
// break;
// default:
// throw new System.NotSupportedException($"AyaNova.BLL.BizObjectNameFetcher::Name type {aytype.ToString()} is not supported");
// }
// cmd.CommandText = $"SELECT m.{COLUMN} FROM {TABLE} AS m WHERE m.id = {id} LIMIT 1";
// using (var dr = cmd.ExecuteReader())
// return dr.Read() ? dr.GetString(0) : "UNKNOWN";
// }
/////////////////////////////////////////////////////////////////////
}//eoc
}//eons

View File

@@ -200,8 +200,6 @@ namespace AyaNova.Biz
.Take(pagingOptions.Limit.Value)
.ToArrayAsync();
// var totalRecordCount = await ct.Widget.CountAsync();
var totalRecordCount = await ct.Widget
.AsNoTracking()
.FromSql(q)
@@ -216,51 +214,88 @@ namespace AyaNova.Biz
//get picklist (paged)
internal async Task<ApiPagedResponse<NameIdItem>> GetPickListAsync(IUrlHelper Url, string routeName, PagingOptions pagingOptions, string q)
internal async Task<ApiPagedResponse<NameIdItem>> GetPickListAsync(IUrlHelper Url, string routeName, PagingOptions pagingOptions)
{
pagingOptions.Offset = pagingOptions.Offset ?? PagingOptions.DefaultOffset;
pagingOptions.Limit = pagingOptions.Limit ?? PagingOptions.DefaultLimit;
NameIdItem[] items;
int totalRecordCount = 0;
// NameIdItem[] items;
// int totalRecordCount = 0;
if (!string.IsNullOrWhiteSpace(q))
{
items = await ct.Widget
.AsNoTracking()
.Where(m => EF.Functions.ILike(m.Name, q))
.OrderBy(m => m.Name)
.Skip(pagingOptions.Offset.Value)
.Take(pagingOptions.Limit.Value)
.Select(m => new NameIdItem()
{
Id = m.Id,
Name = m.Name
}).ToArrayAsync();
// //BUILD THE QUERY
// //base query
// var q = "SELECT id, name FROM AWIDGET ";
totalRecordCount = await ct.Widget.Where(m => EF.Functions.ILike(m.Name, q)).CountAsync();
}
else
{
items = await ct.Widget
.AsNoTracking()
.OrderBy(m => m.Name)
.Skip(pagingOptions.Offset.Value)
.Take(pagingOptions.Limit.Value)
.Select(m => new NameIdItem()
{
Id = m.Id,
Name = m.Name
}).ToArrayAsync();
// //GET THE FILTER / SORT
// if (pagingOptions.DataFilterId > 0)
// {
// var TheFilter = await ct.DataFilter.FirstOrDefaultAsync(x => x.Id == pagingOptions.DataFilterId);
totalRecordCount = await ct.Widget.CountAsync();
}
// //BUILD WHERE AND APPEND IT
// q = q + FilterSqlCriteriaBuilder.DataFilterToSQLCriteria(TheFilter, WidgetBiz.FilterOptions(), UserId);
// //BUILD ORDER BY AND APPEND IT
// q = q + FilterSqlOrderByBuilder.DataFilterToSQLOrderBy(TheFilter);
// }
// else
// {
// //GET DEFAULT ORDER BY
// q = q + FilterSqlOrderByBuilder.DefaultOrderBy();
// }
// #pragma warning disable EF1000
var pageLinks = new PaginationLinkBuilder(Url, routeName, null, pagingOptions, totalRecordCount).PagingLinksObject();
// var items = await ct.Widget
// .AsNoTracking()
// .FromSql(q)
// .Skip(pagingOptions.Offset.Value)
// .Take(pagingOptions.Limit.Value)
// .ToArrayAsync();
ApiPagedResponse<NameIdItem> pr = new ApiPagedResponse<NameIdItem>(items, pageLinks);
// var totalRecordCount = await ct.Widget
// .AsNoTracking()
// .FromSql(q)
// .CountAsync();
// #pragma warning restore EF1000
// if (!string.IsNullOrWhiteSpace(q))
// {
// items = await ct.Widget
// .AsNoTracking()
// .Where(m => EF.Functions.ILike(m.Name, q))
// .OrderBy(m => m.Name)
// .Skip(pagingOptions.Offset.Value)
// .Take(pagingOptions.Limit.Value)
// .Select(m => new NameIdItem()
// {
// Id = m.Id,
// Name = m.Name
// }).ToArrayAsync();
// totalRecordCount = await ct.Widget.Where(m => EF.Functions.ILike(m.Name, q)).CountAsync();
// }
// else
// {
// items = await ct.Widget
// .AsNoTracking()
// .OrderBy(m => m.Name)
// .Skip(pagingOptions.Offset.Value)
// .Take(pagingOptions.Limit.Value)
// .Select(m => new NameIdItem()
// {
// Id = m.Id,
// Name = m.Name
// }).ToArrayAsync();
// totalRecordCount = await ct.Widget.CountAsync();
// }
var ret = PickListFetcher.GetPickList(ct, UserId, pagingOptions, "awidget");
var pageLinks = new PaginationLinkBuilder(Url, routeName, null, pagingOptions, ret.TotalRecordCount).PagingLinksObject();
ApiPagedResponse<NameIdItem> pr = new ApiPagedResponse<NameIdItem>(ret.Items, pageLinks);
return pr;
}

View File

@@ -0,0 +1,10 @@
namespace AyaNova.Models
{
public partial class PickListResult
{
public int TotalRecordCount { get; set; }
public NameIdItem[] Items { get; set; }
}
}

View File

@@ -12,6 +12,107 @@ namespace raven_integration
public class WidgetLists
{
/// <summary>
///
/// </summary>
[Fact]
public async void PickListSortByFieldAscendingWorks()
{
var WidgetNameStart = Util.Uniquify("PickListSortByFieldAscendingWorks");
//CREATE 3 TEST WIDGETS TO TEST ORDER
long FirstInOrderWidgetId = 0;
long SecondInOrderWidgetId = 0;
long ThirdInOrderWidgetId = 0;
dynamic w = new JObject();
w.name = Util.Uniquify(WidgetNameStart);
w.startDate = DateTime.Now;
w.endDate = DateTime.Now.AddHours(1);
ApiResponse a = await Util.PostAsync("Widget", await Util.GetTokenAsync("manager", "l3tm3in"), w.ToString());
Util.ValidateDataReturnResponseOk(a);
FirstInOrderWidgetId = a.ObjectResponse["data"]["id"].Value<long>();
w = new JObject();
w.name = Util.Uniquify(WidgetNameStart);
w.startDate = DateTime.Now.AddHours(1);
w.endDate = DateTime.Now.AddHours(2);
a = await Util.PostAsync("Widget", await Util.GetTokenAsync("manager", "l3tm3in"), w.ToString());
Util.ValidateDataReturnResponseOk(a);
SecondInOrderWidgetId = a.ObjectResponse["data"]["id"].Value<long>();
w = new JObject();
w.name = Util.Uniquify(WidgetNameStart);
w.startDate = DateTime.Now.AddHours(2);
w.endDate = DateTime.Now.AddHours(3);
a = await Util.PostAsync("Widget", await Util.GetTokenAsync("manager", "l3tm3in"), w.ToString());
Util.ValidateDataReturnResponseOk(a);
ThirdInOrderWidgetId = a.ObjectResponse["data"]["id"].Value<long>();
//CREATE FILTER
dynamic d = new JObject();
d.name = Util.Uniquify(WidgetNameStart);
d["public"] = true;
d.listKey = "widget";
//FILTER IN BY NAME FOR TESTING THIS RUN ONLY
dynamic dfilter = new JArray();
//name starts with filter to constrict to widgets that this test block created only
dynamic DataFilterNameStart = new JObject();
DataFilterNameStart.fld = "name";
DataFilterNameStart.op = Util.OpStartsWith;
DataFilterNameStart.value = WidgetNameStart;
dfilter.Add(DataFilterNameStart);
d.filter = dfilter.ToString();
//SORT ORDER ###################
dynamic dsortarray = new JArray();
dynamic dsort = new JObject();
dsort.fld = "startdate";
dsort.dir = "+";
dsortarray.Add(dsort);
d.sort = dsortarray.ToString();
a = await Util.PostAsync("DataFilter", await Util.GetTokenAsync("manager", "l3tm3in"), d.ToString());
Util.ValidateDataReturnResponseOk(a);
long DataFilterId = a.ObjectResponse["data"]["id"].Value<long>();
//NOW FETCH WIDGET LIST WITH FILTER
a = await Util.GetAsync($"Widget/picklist?Offset=0&Limit=999&DataFilterId={DataFilterId.ToString()}", await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateDataReturnResponseOk(a);
Util.ValidateHTTPStatusCode(a, 200);
//assert contains exactly 3 records
((JArray)a.ObjectResponse["data"]).Count.Should().Be(3);
//assert the order returned
a.ObjectResponse["data"][0]["id"].Value<long>().Should().Be(FirstInOrderWidgetId);
a.ObjectResponse["data"][1]["id"].Value<long>().Should().Be(SecondInOrderWidgetId);
a.ObjectResponse["data"][2]["id"].Value<long>().Should().Be(ThirdInOrderWidgetId);
a = await Util.DeleteAsync("Widget/" + FirstInOrderWidgetId.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateHTTPStatusCode(a, 204);
a = await Util.DeleteAsync("Widget/" + SecondInOrderWidgetId.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateHTTPStatusCode(a, 204);
a = await Util.DeleteAsync("Widget/" + ThirdInOrderWidgetId.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateHTTPStatusCode(a, 204);
//DELETE DATAFILTER
a = await Util.DeleteAsync("DataFilter/" + DataFilterId.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateHTTPStatusCode(a, 204);
}
/// <summary>
///
/// </summary>