Files
raven/server/AyaNova/PickList/PickListSqlBuilder.cs
2020-03-13 21:51:12 +00:00

171 lines
6.3 KiB
C#

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<string> 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<string> lSelect = new List<string>();
string ActiveWhereFragment = string.Empty;
List<string> lWhere = new List<string>();
List<string> lOrderBy = new List<string>();
//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