using System.Collections.Generic; using System.Text; using System.Linq; using AyaNova.Biz; namespace AyaNova.PickList { internal static class PickListSqlBuilder { //Maximum number of results to return at any given time //did a little research and may adjust this but it can be fairly girthy in this day and age //and many people might not want or need to autocomplete type if we provide enough leeway. //for example, if you're selecting a const int MAXIMUM_RESULT_COUNT = 100; //Build the query for a picklist request internal static string Build(IAyaPickList pickList, List templateColumnNames, string autoCompleteQuery, bool IncludeInactive) { //TODO: custom template routes and tests //TODO: TESTS FOR ALL FORMS OF QUERY (tags, non text fields etc) //TODO: Clean out unnneeded stuff in AyaPickListFieldDefinition (stuff from datalist copied over) //determine this in advance as it will be used in a loop later bool HasAutoCompleteQuery = !string.IsNullOrWhiteSpace(autoCompleteQuery); //lists to collect the clauses so to avoid comma fuckery List lSelect = new List(); string ActiveWhereFragment = string.Empty; List lWhere = new List(); List lOrderBy = new List(); //Add rowid column as it's always required AyaPickListFieldDefinition rowIdColumn = pickList.ColumnDefinitions.FirstOrDefault(x => x.IsRowId == true); //this should only happen with a development error if (rowIdColumn == null) throw new System.ArgumentNullException($"DEV ERROR in PickListSqlBuilder.cs: picklist for {pickList.DefaultListObjectType.ToString()} has no rowId column specified in columnDefinitions list"); lSelect.Add(rowIdColumn.SqlIdColumnName + " AS rowid"); //add active only as default for all lists unless inactive is specified if (!IncludeInactive) { AyaPickListFieldDefinition activeColumn = pickList.ColumnDefinitions.FirstOrDefault(x => x.IsActiveColumn == true); //it's ok if there is no active column, it could happen so just roll with it if (activeColumn != null) { lSelect.Add(activeColumn.SqlValueColumnName); ActiveWhereFragment = activeColumn.SqlValueColumnName + " = true"; } } foreach (string ColumnName in templateColumnNames) { AyaPickListFieldDefinition o = pickList.ColumnDefinitions.FirstOrDefault(x => x.FieldKey == ColumnName); #if (DEBUG) if (o == null) { throw new System.ArgumentNullException($"DEV ERROR in PickListSqlBuilder.cs: field {ColumnName} specified in template was NOT found in columnDefinitions list"); } #endif if (o != null) {//Ignore missing fields in production var valueColumnName = o.GetSqlValueColumnName(); lSelect.Add(valueColumnName); lOrderBy.Add(valueColumnName); if (HasAutoCompleteQuery) { string sWhere = string.Empty; //Tag? if (o.ColumnDataType == UiFieldDataType.Tags) { //awidget.tags @> array['blah','blah3'::varchar(255)] //or in real life: ((awidget.name like '%o34%') or (awidget.tags @> array['zone-0'::varchar(255)]) ) //but this means exact match only, not like comparison here //This also works: ((awidget.name like '%o34%') or ('blue' like any(awidget.tags)) ) //but again, not a like query only exact match //THIS is the one: //(array_to_string(awidget.tags,',') like '%zo%') sWhere = $"(array_to_string({valueColumnName},',') like '%{autoCompleteQuery}%')"; } else if (o.ColumnDataType == UiFieldDataType.Text || o.ColumnDataType == UiFieldDataType.EmailAddress || o.ColumnDataType == UiFieldDataType.HTTP) { //regular text field sWhere = $"({valueColumnName} LIKE '%{autoCompleteQuery}%')"; } else { //needs to be cast to text //(cast (awidget.serial as text) like '%some%') sWhere = $"(cast ({valueColumnName} as text) LIKE '%{autoCompleteQuery}%')"; } lWhere.Add(sWhere); } } } StringBuilder sb = new StringBuilder(); //SELECT sb.Append("select "); foreach (string s in lSelect) { sb.Append(s); sb.Append(","); } //clear trailing comma sb.Length--; //FROM sb.Append(" "); sb.Append(pickList.SQLFrom); //WHERE sb.Append(" where "); if (!IncludeInactive) { sb.Append(ActiveWhereFragment); sb.Append(" and ("); } foreach (string s in lWhere) { sb.Append(s); sb.Append(" or "); } //clear trailing or sb.Length -= 4; //enclosing parenthesis if (!IncludeInactive) { sb.Append(")"); } //ORDER BY sb.Append(" order by "); foreach (string s in lOrderBy) { sb.Append(s); sb.Append(","); } //clear trailing comma sb.Length--; //LIMIT sb.Append($" limit {MAXIMUM_RESULT_COUNT}"); return sb.ToString(); } }//eoc }//ens