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; using EnumsNET; namespace AyaNova.DataList { internal static class DataListFetcher { internal static async Task GetResponseAsync(string DataListKey, AyContext ct, ListOptions listOptions, long UserId, AuthorizationRoles UserRoles) { var DataList = DataListFactory.GetAyaDataList(DataListKey); //was the name not found as a list? if (DataList == null) { throw new System.ArgumentOutOfRangeException($"DataList \"{DataListKey}\" specified does not exist"); } //check rights if (!UserRoles.HasAnyFlags(DataList.AllowedRoles)) throw new System.UnauthorizedAccessException("User roles insufficient for this datalist"); //do we need to default the listView? if (string.IsNullOrWhiteSpace(listOptions.ListView)) { listOptions.ListView = DataList.DefaultListView; } //parse the list view var ListViewArray = JArray.Parse(listOptions.ListView); //Get the field key names in a list from the listview List ListViewFieldList = DataList.GetFieldListFromListView(ListViewArray); //BUILD THE QUERY //SELECT FRAGMENT COLUMNS FROM TEMPLATE var SelectBuild = DataListSqlSelectBuilder.Build(DataList.FieldDefinitions, ListViewFieldList); //FROM CLAUSE var qFrom = DataList.SQLFrom; var qWhere = string.Empty; var qOrderBy = string.Empty; //WHERE CLAUSE - FILTER qWhere = DataListSqlFilterCriteriaBuilder.DataFilterToSQLCriteria(DataList.FieldDefinitions, ListViewArray, UserId); //ORDER BY CLAUSE - SORT //BUILD ORDER BY qOrderBy = DataListSqlFilterOrderByBuilder.DataFilterToSQLOrderBy(DataList.FieldDefinitions, ListViewArray); //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; qDataQuery = $"{SelectBuild.Select} {qFrom} {qWhere} {qOrderBy} {qLimitOffset}".Replace(" ", " "); qTotalRecordsQuery = $"SELECT COUNT(*) {qFrom} {qWhere}".Replace(" ", " "); //RETURN OBJECTS int returnRowColumnCount = ListViewFieldList.Count(); List> rows = new List>(); long totalRecordCount = 0; //QUERY THE DB using (var command = ct.Database.GetDbConnection().CreateCommand()) { await ct.Database.OpenConnectionAsync(); //GET DATA RETURN ROWS command.CommandText = qDataQuery; using (var dr = await command.ExecuteReaderAsync()) { while (dr.Read()) { List row = new List(returnRowColumnCount); //INSERT REMAINING FIELDS FROM TEMPLATE INTO THE RETURN ROWS LIST foreach (string TemplateField in ListViewFieldList) { //get the AyaObjectFieldDefinition AyaDataListFieldDefinition f = DataList.FieldDefinitions.FirstOrDefault(x => x.FieldKey == TemplateField); if (f.IsCustomField) { AyaFieldData AyaField = new AyaFieldData(); var cust = dr.GetString(SelectBuild.map[f.GetSqlValueColumnName()]); if (!string.IsNullOrWhiteSpace(cust)) { JObject j = JObject.Parse(cust); //convert field name to cust name then get value var InternalCustomFieldName = AyaFormFieldDefinitions.TranslateLTCustomFieldToInternalCustomFieldName(TemplateField); //Sometimes a custom field is specified but doesn't exist in the collection so don't assume it's there // AyaField.v = j[InternalCustomFieldName].Value(); JToken o = j[InternalCustomFieldName]; if (o != null) AyaField.v = o.Value(); else AyaField.v = null; row.Add(AyaField); } /* TODO: Custom field handling GetName works just not with multipart identifiers I could force naming by making all fields and AS, or I could map the ordinal when generating the Select fields so that I have a map to refer to here mapping in advance actually makes a lot of sense, then no more of this fragility of going by pointer index and hoping for the best it would just be premapped out. dr.GetOrdinal(f.SqlValueColumnName) 'dr.GetOrdinal(f.SqlValueColumnName)' threw an exception of type 'System.IndexOutOfRangeException' f.SqlValueColumnName "awidget.customfields" dr.GetName(nCurrentColumnPointer) "customfields" dr.GetOrdinal("customfields"); 5 */ } else { AyaFieldData AyaField = new AyaFieldData(); AyaField.v = dr.GetValue(SelectBuild.map[f.GetSqlValueColumnName()]); if (f.IsRowId) { AyaField.rid = true; } else { AyaField.rid = null; } if (f.SqlIdColumnName != null) { var ordinal = SelectBuild.map[f.SqlIdColumnName]; if (!await dr.IsDBNullAsync(ordinal)) AyaField.i = dr.GetInt64(ordinal); } row.Add(AyaField); } } rows.Add(row); } } //GET TOTAL RECORD COUNT command.CommandText = qTotalRecordsQuery; using (var dr = await command.ExecuteReaderAsync()) { if (dr.Read()) { totalRecordCount = dr.GetInt64(0); } } } //BUILD THE COLUMNS RETURN PROPERTY JSON FRAGMENT Newtonsoft.Json.Linq.JArray ColumnsJSON = null; ColumnsJSON = DataList.GenerateListColumnsJSONFromListView(ListViewArray); return new ApiDataListResponse(rows, totalRecordCount, ColumnsJSON); } }//eoc }//eons