From d032ceb125fc805ea34f24b2088c35dd3bfb8ddb Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Thu, 13 Feb 2020 23:03:05 +0000 Subject: [PATCH] --- .../core-list-graph-datatable-filter-sort.txt | 4 +- .../DataListSqlFilterCriteriaBuilder.cs | 90 +++++++++++++++---- .../DataListSqlFilterOrderByBuilder.cs | 51 ++++++----- .../DataList/DataListSqlSelectBuilder.cs | 4 +- 4 files changed, 104 insertions(+), 45 deletions(-) diff --git a/devdocs/specs/core-list-graph-datatable-filter-sort.txt b/devdocs/specs/core-list-graph-datatable-filter-sort.txt index 51e1af50..13d490a0 100644 --- a/devdocs/specs/core-list-graph-datatable-filter-sort.txt +++ b/devdocs/specs/core-list-graph-datatable-filter-sort.txt @@ -48,7 +48,9 @@ DataListView JSON: Sort property definition ID VS NAME -if it's an name *and* id field +if it's an name *and* id field it won't matter because it will sort by name only +I've thought about it and can't see a use case for needing to sort by the underlying ID value, but if people want that they can just not sort the list to get +the most recent records at the top (for example) Filter object definition: Has an "any" boolean property which if true means make an OR query of the conditions if more than one, if nore present or false it means AND each condition (if more than one) diff --git a/server/AyaNova/DataList/DataListSqlFilterCriteriaBuilder.cs b/server/AyaNova/DataList/DataListSqlFilterCriteriaBuilder.cs index 3b22214f..d9c74735 100644 --- a/server/AyaNova/DataList/DataListSqlFilterCriteriaBuilder.cs +++ b/server/AyaNova/DataList/DataListSqlFilterCriteriaBuilder.cs @@ -14,34 +14,31 @@ namespace AyaNova.DataList public static string DataFilterToSQLCriteria(List objectFieldsList, JArray listViewArray, long userId) { - if (string.IsNullOrWhiteSpace(filterJson)) + if (listViewArray == null || listViewArray.Count == 0) { return ""; } StringBuilder sb = new StringBuilder(); - //iterate the datafilter and concatenate a sql query from it - var FilterArray = JArray.Parse(filterJson); - for (int i = 0; i < FilterArray.Count; i++) + //iterate the list view fields and concatenate a sql query from it + //// [{key:"COLUMN UNIQUE KEY ID",sort:"-" or "+",filter:{any:true/false,items:[{FILTER OBJECT SEE BELOW}]} }, {key:"second column unique key"},{...etc...}] + for (int i = 0; i < listViewArray.Count; i++) { - var filterItem = FilterArray[i]; - var fld = filterItem["fld"].Value(); - var opType = filterItem["op"].Value(); - List tagList = new List(); - string val = string.Empty; - if (filterItem["value"].Type != JTokenType.Array) - val = filterItem["value"].Value(); - else + var cm = listViewArray[i]; + //skip it if sort is not defined + if (cm["filter"] == null) { - tagList = filterItem["value"].ToObject>(); + continue; } - var dataType = objectFieldsList.Find(x => x.FieldKey.ToLowerInvariant() == fld).UiFieldDataType; + //Yup there's at least one filter here for this column sb.Append("("); - //Get the correct sql column name + //Get some info about this column / field + var fld = cm["fld"].Value(); + var dataType = objectFieldsList.Find(x => x.FieldKey.ToLowerInvariant() == fld).UiFieldDataType; AyaDataListFieldDefinition DataListField = objectFieldsList.FirstOrDefault(x => x.FieldKey == fld); #if (DEBUG) //Developers little helper @@ -51,14 +48,71 @@ namespace AyaNova.DataList } #endif var SQLValueColumnName = DataListField.GetSqlValueColumnName(); - sb.Append(DataFilterToColumnCriteria(SQLValueColumnName, (UiFieldDataType)dataType, opType, val, tagList, userId)); - if (i < FilterArray.Count - 1) + var SQLIdColumnName = DataListField.SqlIdColumnName; + + //get filter items collection for this field view definition + var filterItems = (JArray)cm["filter"]["items"]; + + var IsOrFilter = false; + if (cm["filter"]["any"] != null) + { + IsOrFilter = cm["filter"]["any"].Value(); + } + + //Is there more than one filter for this column? + if (filterItems.Count > 1) + { + //Yup, so put the whole group in paranthesis + sb.Append("("); + } + + //Iterate filter items building this WHERE segment + for (int y = 0; y < filterItems.Count; y++) + { + //Put this item in parenthesis + sb.Append("("); + var filterItem = (JObject)filterItems[y]; + + var opType = filterItem["op"].Value(); + List tagList = new List(); + string val = string.Empty; + if (filterItem["value"].Type != JTokenType.Array) + val = filterItem["value"].Value(); + else + { + tagList = filterItem["value"].ToObject>(); + } + + sb.Append(DataFilterToColumnCriteria(SQLValueColumnName, (UiFieldDataType)dataType, opType, val, tagList, userId)); + + //close this item parenthesis + if (y < filterItems.Count - 1) + { + if (IsOrFilter) + sb.Append(") OR "); + else + sb.Append(") AND "); + } + else + { + sb.Append(")"); + } + + + } + if (filterItems.Count > 1) + { + //close this group + sb.Append(")"); + } + + if (i < listViewArray.Count - 1) { sb.Append(") AND "); } } - return " where " + sb.ToString() + ")"; + return " where (" + sb.ToString() + ")"; } /// diff --git a/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs b/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs index a539f05a..30920f94 100644 --- a/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs +++ b/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs @@ -15,31 +15,20 @@ namespace AyaNova.DataList public static string DataFilterToSQLOrderBy(List objectFieldsList, JArray listViewArray) { - if ( string.IsNullOrWhiteSpace(SortJson)) - { - //sort by default field descending which should in theory always be the id column of the main object in the list - //which should return the results to user with most recent records at the top if no sort order was specified - if (objectFieldsList[0].FieldKey == "df") - { - return $"ORDER BY {objectFieldsList[0].SqlIdColumnName} DESC"; - } - else - { - //no default column so no idea how to sort - return string.Empty; - } - } - StringBuilder sb = new StringBuilder(); //iterate the datafilter and concatenate a sql query from it - var SortArray = JArray.Parse(SortJson); - for (int i = 0; i < SortArray.Count; i++) + // [{key:"COLUMN UNIQUE KEY ID",sort:"-" or "+",filter:{any:true/false,items:[{FILTER OBJECT SEE BELOW}]} }, {key:"second column unique key"},{...etc...}] + for (int i = 0; i < listViewArray.Count; i++) { - - var SortItem = SortArray[i]; - var fld = SortItem["fld"].Value(); - var dir = SortItem["dir"].Value(); + var cm = listViewArray[i]; + //skip it if sort is not defined + if (cm["sort"] == null) + { + continue; + } + var fld = cm["fld"].Value(); + var dir = cm["sort"].Value(); //Get the correct sql column name AyaDataListFieldDefinition DataListField = objectFieldsList.FirstOrDefault(x => x.FieldKey == fld); #if (DEBUG) @@ -56,13 +45,29 @@ namespace AyaNova.DataList sb.Append(" "); sb.Append(dir == "+" ? "ASC" : "DESC"); - if (i < SortArray.Count - 1) + if (i < listViewArray.Count - 1) { sb.Append(","); } } - return "ORDER BY" + sb.ToString(); + if (sb.Length == 0) + { + //no sort specified so default it + if (objectFieldsList[0].FieldKey == "df") + { + return $"ORDER BY {objectFieldsList[0].SqlIdColumnName} DESC"; + } + else + { + //no default column so no idea how to sort + return string.Empty; + } + } + else + { + return "ORDER BY" + sb.ToString(); + } } diff --git a/server/AyaNova/DataList/DataListSqlSelectBuilder.cs b/server/AyaNova/DataList/DataListSqlSelectBuilder.cs index c76fde43..4e3bbb5d 100644 --- a/server/AyaNova/DataList/DataListSqlSelectBuilder.cs +++ b/server/AyaNova/DataList/DataListSqlSelectBuilder.cs @@ -15,9 +15,7 @@ namespace AyaNova.DataList //Build the SELECT portion of a list query based on the template, mini or full and the object key in question internal static string Build(List objectFieldsList, JArray listViewArray) { - - //parse the template - var jtemplate = JObject.Parse(template); + //convert to strings array (https://stackoverflow.com/a/33836599/8939)