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