diff --git a/server/AyaNova/biz/ObjectFields.cs b/server/AyaNova/biz/ObjectFields.cs index 508f8dd4..b2a2bf7e 100644 --- a/server/AyaNova/biz/ObjectFields.cs +++ b/server/AyaNova/biz/ObjectFields.cs @@ -226,42 +226,27 @@ namespace AyaNova.Biz from awidget left outer join auser on (awidget.userid=auser.id) left outer join auseroptions on (auser.id=auseroptions.userid) - - public string Key { get; set; } - public string PropertyName { get; set; } - public bool Hideable { get; set; } - public bool SharedLTKey { get; set; } - public bool Custom { get; set; } - public bool Filterable { get; set; } - public bool Sortable { get; set; } - public bool MiniAvailable { get; set; } - public int UiFieldDataType { get; set; } - //If it's an enum DataType then this is the specific enum type which sb the name of the class that holds the enum in the server project - public string EnumType { get; set; } - //if field is a reference to another object (i.e. a client in a workorders list) - //then the type to open is set here - public int AyObjectType { get; set; } - - //For query building - //This is the equivalent of the v7 SqlColumnNameAttribute - public string SqlIdColumn { get; set; } - public string SqlColumn { get; set; } */ + + //THIS is strictly a list object, not for forms so it doesn't need hideable set to any as that's a customization thing l.Add(new ObjectField { Key = "df", AyObjectType = (int)AyaType.Widget }); l.Add(new ObjectField { Key = "WidgetName", - PropertyName = "widgetname", - UiFieldDataType = (int)AyaUiFieldDataType.Text, - Hideable = false, + PropertyName = "widgetname",//same as sql display column so no need to specify both + UiFieldDataType = (int)AyaUiFieldDataType.Text, AyObjectType = (int)AyaType.Widget, - SqlIdColumn = "widgetid", - SqlDisplayColumn = "widgetname" - });//not hideable for strictly list must mean it has to be in template? - - l.Add(new ObjectField { Key = "User", PropertyName = "userid", UiFieldDataType = (int)AyaUiFieldDataType.Text, AyObjectType = (int)AyaType.User }); - l.Add(new ObjectField { Key = "Name", PropertyName = "Name", SharedLTKey = true, UiFieldDataType = (int)AyaUiFieldDataType.Text, Hideable = false }); - l.Add(new ObjectField { Key = "UserEmailAddress", PropertyName = "Emailaddress", UiFieldDataType = (int)AyaUiFieldDataType.EmailAddress, SqlDisplayColumn = "emailaddress" }); + SqlIdColumn = "widgetid" + }); + l.Add(new ObjectField + { + Key = "User", + PropertyName = "username",//same as sql display column so no need to specify both + UiFieldDataType = (int)AyaUiFieldDataType.Text, + AyObjectType = (int)AyaType.User, + SqlIdColumn = "userid" + }); + l.Add(new ObjectField { Key = "UserEmailAddress", PropertyName = "emailaddress", UiFieldDataType = (int)AyaUiFieldDataType.EmailAddress}); break; #endregion @@ -358,8 +343,8 @@ namespace AyaNova.Biz public bool Custom { get; set; } public bool Filterable { get; set; } public bool Sortable { get; set; } - //had this but don't know why - //if a user wants to shove a bunch of notes into a single column with other shit that's their lookout surely + //had this but don't know why + //if a user wants to shove a bunch of notes into a single column with other shit that's their lookout surely //public bool MiniAvailable { get; set; } public int UiFieldDataType { get; set; } //If it's an enum DataType then this is the specific enum type which sb the name of the class that holds the enum in the server project @@ -380,13 +365,14 @@ namespace AyaNova.Biz SharedLTKey = false; Hideable = true; Custom = false; - Filterable = true; - Sortable = true; + Filterable = true; + Sortable = true; //Set openable object type to no type which is the default and means it's not a link to another object AyObjectType = (int)AyaType.NoType; } + //Get column to query for display name or use PropertyName if there is no difference public string GetSqlDisplayColumnName() { if (string.IsNullOrEmpty(SqlDisplayColumn)) diff --git a/server/AyaNova/biz/WidgetBiz.cs b/server/AyaNova/biz/WidgetBiz.cs index 6221acea..acdf4737 100644 --- a/server/AyaNova/biz/WidgetBiz.cs +++ b/server/AyaNova/biz/WidgetBiz.cs @@ -270,7 +270,8 @@ namespace AyaNova.Biz - //get many (paged) + //Generic list of widgets + #region GetList internal async Task GetList(IUrlHelper Url, string routeName, ListOptions listOptions) { @@ -338,7 +339,7 @@ namespace AyaNova.Biz qTotalRecordsQuery = $"SELECT COUNT(*) {qFrom}"; } - + //RETURN OBJECTS List items = new List(); long totalRecordCount = 0; @@ -365,15 +366,15 @@ namespace AyaNova.Biz if (dr.Read()) { totalRecordCount = dr.GetInt64(0); - } + } } } -//TODO: Build the return object in a clean format -//rows:{[ {},{v:"Green mechanics",id:32},{v:"...notes..."},{v:"42",id:42}, ...thousands more etc.... ]} + //TODO: Build the return object in a clean format + //rows:{[ {},{v:"Green mechanics",id:32},{v:"...notes..."},{v:"42",id:42}, ...thousands more etc.... ]} + + - - //BUILD THE PAGING LINKS PORTION var pageLinks = new PaginationLinkBuilder(Url, routeName, null, listOptions, totalRecordCount).PagingLinksObject(); @@ -401,77 +402,140 @@ namespace AyaNova.Biz return pr; } + #endregion - // //get many (paged) - // internal async Task> GetManyAsync(IUrlHelper Url, string routeName, ListOptions pagingOptions) - // { - // pagingOptions.Offset = pagingOptions.Offset ?? ListOptions.DefaultOffset; - // pagingOptions.Limit = pagingOptions.Limit ?? ListOptions.DefaultLimit; - - // //BUILD THE QUERY - // //base query - // var q = "SELECT *, xmin FROM AWIDGET "; - - // //GET THE FILTER / SORT - // if (pagingOptions.DataFilterId > 0) - // { - // var TheFilter = await ct.DataFilter.FirstOrDefaultAsync(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.DefaultGetManyOrderBy(); - // } + //TEST WIDGET->USER->EMAILADDRESS multi table list + #region TestGetWidgetUserEmailList + internal async Task TestGetWidgetUserEmailList(IUrlHelper Url, string routeName, ListOptions listOptions) + { - // #pragma warning disable EF1000 - // var items = await ct.Widget - // .FromSqlRaw(q) - // .AsNoTracking() - // .Skip(pagingOptions.Offset.Value) - // .Take(pagingOptions.Limit.Value) - // .ToArrayAsync(); + //TODO: Get template (MOCKED FOR NOW UNTIL PROOF OF CONCEPT) + var MOCK_WIDGET_DISPLAY_TEMPLATE_JSON = @" + { + ""full"":[""WidgetName"",""WidgetSerial"",""WidgetDollarAmount"",""WidgetRoles"",""WidgetStartDate"",""Active""], + ""mini"":[""WidgetName"",""WidgetSerial""] + } + "; - // var totalRecordCount = await ct.Widget - // .FromSqlRaw(q) - // .AsNoTracking() - // .CountAsync(); - // #pragma warning restore EF1000 + //BUILD THE QUERY - // var pageLinks = new PaginationLinkBuilder(Url, routeName, null, pagingOptions, totalRecordCount).PagingLinksObject(); + //SELECT FRAGMENT COLUMNS FROM TEMPLATE + //"select clm,clm,clm" + var qSelectColumns = SqlSelectBuilder.Build(ObjectFields.WIDGET_KEY, MOCK_WIDGET_DISPLAY_TEMPLATE_JSON, listOptions.Mini); - // ApiPagedResponse pr = new ApiPagedResponse(items, pageLinks); - // return pr; - // } + var qFrom = "FROM AWIDGET"; + + //FILTERED? + DataFilter TheFilter = null; + if (listOptions.DataFilterId > 0) + { + TheFilter = await ct.DataFilter.FirstOrDefaultAsync(x => x.Id == listOptions.DataFilterId); + } + + //WHERE CLAUSE - FILTER + var qWhere = string.Empty; + if (listOptions.DataFilterId > 0) + { + qWhere = SqlFilterCriteriaBuilder.DataFilterToSQLCriteria(TheFilter, ObjectFields.ObjectFieldsList(ObjectFields.WIDGET_KEY), UserId); + } + + //ORDER BY CLAUSE - SORT + var qOrderBy = string.Empty; + if (listOptions.DataFilterId > 0) + { + //BUILD ORDER BY AND APPEND IT + qOrderBy = SqlFilterOrderByBuilder.DataFilterToSQLOrderBy(TheFilter); + } + else + { + //GET DEFAULT ORDER BY + qOrderBy = SqlFilterOrderByBuilder.DefaultGetManyOrderBy(); + } + + //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}"; + } - // /// - // /// Get PickList - // /// - // /// - // /// - // /// - // /// - // internal ApiPagedResponse GetPickList(IUrlHelper Url, string routeName, ListOptions pagingOptions) - // { - // pagingOptions.Offset = pagingOptions.Offset ?? ListOptions.DefaultOffset; - // pagingOptions.Limit = pagingOptions.Limit ?? ListOptions.DefaultLimit; - // var ret = PickListFetcher.GetPickList(ct, UserId, pagingOptions, FilterOptions(), "awidget"); - // var pageLinks = new PaginationLinkBuilder(Url, routeName, null, pagingOptions, ret.TotalRecordCount).PagingLinksObject(); - // ApiPagedResponse pr = new ApiPagedResponse(ret.Items, pageLinks); - // return pr; - // } + //RETURN OBJECTS + List items = new List(); + long totalRecordCount = 0; + + //RUN THE QUERY + using (var command = ct.Database.GetDbConnection().CreateCommand()) + { + + ct.Database.OpenConnection(); + command.CommandText = qDataQuery; + using (var dr = command.ExecuteReader()) + { + while (dr.Read()) + { + object[] row = new object[dr.FieldCount]; + dr.GetValues(row); + items.Add(row); + } + } + + command.CommandText = qTotalRecordsQuery; + using (var dr = command.ExecuteReader()) + { + if (dr.Read()) + { + totalRecordCount = dr.GetInt64(0); + } + } + } + + //TODO: Build the return object in a clean format + //rows:{[ {},{v:"Green mechanics",id:32},{v:"...notes..."},{v:"42",id:42}, ...thousands more etc.... ]} + //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 = ObjectFields.GenerateMINIListColumnsJSON(AyaType.Widget); + } + else + { + ColumnsJSON = ObjectFields.GenerateListColumnsJSONFromTemplate(AyaType.Widget, ObjectFields.WIDGET_KEY, MOCK_WIDGET_DISPLAY_TEMPLATE_JSON); + } + + //TODO: BUILD THE RETURN LIST OF DATA ITEMS + //If mini format all desired columns in order into the single mini return display (and set the only other return field which is ID) + + //If wide then format the fields in oder chosen (grid sort and filter template has already done that part above) + + //TODO: Genericize the above block of building return when it's working as this code needs to be central and optimized as much as possible + + + ApiPagedResponse pr = new ApiPagedResponse(items, pageLinks, ColumnsJSON); + return pr; + } + #endregion //////////////////////////////////////////////////////////////////////////////////////////////// //VALIDATION