From a678e3d14f735f8dad30bbd2fe97332b0e56cde6 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Tue, 21 Jan 2020 20:28:02 +0000 Subject: [PATCH] --- server/AyaNova/DataList/DataListFetcher.cs | 173 +++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 server/AyaNova/DataList/DataListFetcher.cs diff --git a/server/AyaNova/DataList/DataListFetcher.cs b/server/AyaNova/DataList/DataListFetcher.cs new file mode 100644 index 00000000..569db35d --- /dev/null +++ b/server/AyaNova/DataList/DataListFetcher.cs @@ -0,0 +1,173 @@ +using System.Collections.Generic; +using System.Linq; +using AyaNova.Biz; +using Newtonsoft.Json.Linq; +using AyaNova.Api.ControllerHelpers; +using Microsoft.AspNetCore.Mvc; +using AyaNova.Models; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace AyaNova.DataList +{ + internal static class DataListFetcher + { + internal static async Task GetResponse( + string DataListKey, AyContext ct, IUrlHelper Url, + string routeName, ListOptions listOptions, string JSONDataListTemplate, long UserId) + { + //TODO: Get template (MOCKED FOR NOW UNTIL PROOF OF CONCEPT) + // var MOCK_WIDGET_USER_EMAIL_DISPLAY_TEMPLATE_JSON = @" + // { + // ""full"":[""widgetname"",""username"",""emailaddress"",""widgetactive""], + // ""mini"":[""widgetname"",""username"",""emailaddress""] + // } + // "; + + // var AyaObjectFields = AyaObjectFieldDefinitions.AyaObjectFields(AyaObjectFieldDefinitions.TEST_WIDGET_USER_EMAIL_ADDRESS_LIST_KEY); + var DataList=DataListFactory.GetAyaDataList(nameof(TestWidgetUserEmailDataList)); + + + //TODO: PUt this in the template biz class ultimately and modify sqlselectbuilder to use it + + //PARSE THE TEMPLATE INTO A STRING ARRAY + //SO WE KNOW WHICH FIELDS TO RETURN FROM QUERY + var jtemplate = JObject.Parse(JSONDataListTemplate); + + //convert to strings array (https://stackoverflow.com/a/33836599/8939) + string[] templateFieldList; + if (listOptions.Mini) + { + templateFieldList = ((JArray)jtemplate["mini"]).ToObject(); + } + else + { + templateFieldList = ((JArray)jtemplate["full"]).ToObject(); + } + + + //BUILD THE QUERY + //SELECT FRAGMENT COLUMNS FROM TEMPLATE + //TODO: Make this a function called from DataList + var qSelectColumns = DataListSqlSelectBuilder.Build(DataList.FieldDefinitions, JSONDataListTemplate, listOptions.Mini); + + //FROM CLAUSE + //this is where the full SQL statement needs to be made with JOINS etc + //TODO: Can this be moved away into the objectfields or new object + //var qFrom = "from awidget left outer join auser on (awidget.userid=auser.id) left outer join auseroptions on (auser.id=auseroptions.userid)"; + var qFrom=DataList.SQLFrom; + + //FILTERED? + DataFilter TheFilter = null; + var qWhere = string.Empty; + var qOrderBy = string.Empty; + if (listOptions.DataFilterId > 0) + { + TheFilter = await ct.DataFilter.FirstOrDefaultAsync(x => x.Id == listOptions.DataFilterId); + //WHERE CLAUSE - FILTER + qWhere = DataListSqlFilterCriteriaBuilder.DataFilterToSQLCriteria(TheFilter, DataList.FieldDefinitions, UserId); + //ORDER BY CLAUSE - SORT + //BUILD ORDER BY AND APPEND IT + qOrderBy = DataListSqlFilterOrderByBuilder.DataFilterToSQLOrderBy(TheFilter); + } + + //LIMIT AND OFFSET CLAUSE - PAGING + listOptions.Offset = listOptions.Offset ?? ListOptions.DefaultOffset; + listOptions.Limit = listOptions.Limit ?? ListOptions.DefaultLimit; + var qLimitOffset = $"LIMIT {listOptions.Limit} OFFSET {listOptions.Offset}"; + + //PUT IT ALL TOGETHER + string qDataQuery = string.Empty; + string qTotalRecordsQuery = string.Empty; + if (TheFilter != null) + { + qDataQuery = $"{qSelectColumns} {qFrom} {qWhere} {qOrderBy} {qLimitOffset}"; + qTotalRecordsQuery = $"SELECT COUNT(*) {qFrom} {qWhere}"; + } + else + { + qDataQuery = $"{qSelectColumns} {qFrom} {qLimitOffset}"; + qTotalRecordsQuery = $"SELECT COUNT(*) {qFrom}"; + } + + + + //RETURN OBJECTS + int returnRowColumnCount = templateFieldList.Count() + 1;//Templates don't have the DF column in them but we need it and it's in the query so plus one + List> rows = new List>(); + long totalRecordCount = 0; + + //QUERY THE DB + using (var command = ct.Database.GetDbConnection().CreateCommand()) + { + ct.Database.OpenConnection(); + + //GET DATA RETURN ROWS + command.CommandText = qDataQuery; + using (var dr = command.ExecuteReader()) + { + while (dr.Read()) + { + List row = new List(returnRowColumnCount); + + //PROCESS THE DF DEFAULT FIRST COLUMN + //first column is always the underlying id value of the default record to open for this row in the client ui + row.Add(new AyaFieldData() { v = dr.GetInt64(0) }); + + //GetOrdinal by name is flakey in npgsql so just going by field definition and ordinal numerically + int nCurrentColumnPointer = 1;//start at 1 + + //INSERT REMAINING FIELDS FROM TEMPLATE INTO THE RETURN ROWS LIST + foreach (string TemplateField in templateFieldList) + { + //get the AyaObjectFieldDefinition + AyaDataListFieldDefinition f = DataList.FieldDefinitions.FirstOrDefault(x => x.FieldKey == TemplateField); + + AyaFieldData AyaField = new AyaFieldData(); + AyaField.v = dr.GetValue(nCurrentColumnPointer); + nCurrentColumnPointer++; + + if (f.SqlIdColumnName != null)//skip over df column id, it's not there + { + AyaField.i = dr.GetInt64(nCurrentColumnPointer); + nCurrentColumnPointer++; + } + row.Add(AyaField); + } + rows.Add(row); + } + } + + //GET TOTAL RECORD COUNT + command.CommandText = qTotalRecordsQuery; + using (var dr = command.ExecuteReader()) + { + if (dr.Read()) + { + totalRecordCount = dr.GetInt64(0); + } + } + } + + //BUILD THE PAGING LINKS PORTION + var pageLinks = new PaginationLinkBuilder(Url, routeName, null, listOptions, totalRecordCount).PagingLinksObject(); + + //BUILD THE COLUMNS RETURN PROPERTY JSON FRAGMENT + string ColumnsJSON = string.Empty; + if (listOptions.Mini) + { + ColumnsJSON = DataList.GenerateMINIListColumnsJSON(); + } + else + { + ColumnsJSON = DataList.GenerateListColumnsJSONFromTemplate(JSONDataListTemplate); + } + + + ApiPagedResponse pr = new ApiPagedResponse(rows, pageLinks, ColumnsJSON); + return pr; + } + + + }//eoc +}//eons \ No newline at end of file