This commit is contained in:
2018-11-30 23:48:05 +00:00
parent 460d50109f
commit aeeaf0bf30
3 changed files with 856 additions and 3 deletions

View File

@@ -0,0 +1,851 @@
using System.Collections.Generic;
using System;
using System.Globalization;
using System.Text;
namespace AyaNova.Biz
{
public static class FilterSqlCriteriaBuilder
{
/// <summary>
/// Used internally by AyaNova UI to translate Infragistics grid filter settings to AyaNova friendly SQL critiera
/// </summary>
private static string GridToSqlCriteria(string sColumn, string sDataType, string sOperator, string sValue, bool IsCompound)
{
//if(log.IsDebugEnabled)
////case 1039 //log.Debug("GridToSqlCriteria(Column=" + sColumn +", DataType=" + sDataType + ", Operator=" + sOperator + ", Value=" + sValue+")");
StringBuilder sb = new StringBuilder();
//Column name
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
//Added: 13-July-2006 prior fix on the 6th either broke due to other changes or
//was not enough in the first place, oddly it was working then, but this is also needed
//now to make it work:
//Handle bools with null values
//this comes about from a user selecting blanks or nonblanks to filter a bool column
if (sValue == "" && sDataType == "System.Boolean")
{
sValue = "False";
}
//handle null values separately
if (sValue == "")
{
//strings in grids are rarely null, almost always just an empty string
//so filter on that instead
switch (sDataType)
{
case "System.String":
{
if (sOperator == "Equals")
{
//Changed: 19-July-2006 was missing null values, "almost always' above not good enough!
sb.Append("Is Null");
sb.Append(" OR ");
sb.Append(sColumn);
sb.Append(" = ''");
}
else
sb.Append(" <> ''");
}
break;
default:
{
if (sOperator == "Equals")
sb.Append("Is Null");
else
sb.Append("Is Not Null");
}
break;
}
}
else
{//non null value
//Changed 21-March-2006:
//But wait! Both mssql and firebird won't include a null result
//on the filter field so in some cases we need to include them
//i.e. if a value is supposed to be not equal to a specific non-null value
//then null is a valid value to return but won't be normally
//so....
//Special addition to handle nulls
if (!IsCompound)
{
switch (sOperator)
{
case "Equals":
//no change on equals for nulls
break;
case "GreaterThan":
//no change on greater than for nulls
//(nulls are going to be assumed to be always at the
//less than end of the scale)
break;
case "GreaterThanOrEqualTo":
//no change on greater than for nulls
//(nulls are going to be assumed to be always at the
//less than end of the scale)
break;
case "LessThan":
sb.Append("Is Null OR ");
sb.Append(sColumn);
sb.Append(" ");
break;
case "LessThanOrEqualTo":
sb.Append("Is Null OR ");
sb.Append(sColumn);
sb.Append(" ");
break;
case "Like":
//No change on like
break;
case "NotEquals":
//This is the big one:
sb.Append("Is Null OR ");
sb.Append(sColumn);
sb.Append(" ");
break;
}
}
#region Build for specific type
switch (sDataType)
{
case "System.String":
//escape any pre-existing apostrophes
//i.e. "O'Flaherty's pub" would cause fits
//if this wasn't done
//MS-sql and firebird use double apostrophes so
//any future db added should consider this
sValue = sValue.Replace("'", "''");
//case 1951 - unescape ampersands
sValue = sValue.Replace("&amp;", "&");
switch (sOperator)
{
case "Equals":
sb.Append("='");
sb.Append(sValue);
sb.Append("'");
break;
case "GreaterThan":
sb.Append(">'");
sb.Append(sValue);
sb.Append("'");
break;
case "GreaterThanOrEqualTo":
sb.Append(">='");
sb.Append(sValue);
sb.Append("'");
break;
case "LessThan":
sb.Append("<'");
sb.Append(sValue);
sb.Append("'");
break;
case "LessThanOrEqualTo":
sb.Append("<='");
sb.Append(sValue);
sb.Append("'");
break;
case "Like":
sb.Append("Like '");
sb.Append(sValue);
sb.Append("%'");
break;
case "NotEquals":
sb.Append("<>'");
sb.Append(sValue);
sb.Append("'");
break;
//Following 7 operators added 14-June-2006
case "DoesNotContain":
sb.Append("Not Like '%");
sb.Append(sValue);
sb.Append("%'");
break;
case "Contains":
sb.Append("Like '%");
sb.Append(sValue);
sb.Append("%'");
break;
case "StartsWith":
sb.Append("Like '");
sb.Append(sValue);
sb.Append("%'");
break;
case "EndsWith":
sb.Append("Like '%");
sb.Append(sValue);
sb.Append("'");
break;
case "DoesNotStartWith":
sb.Append("Not Like '");
sb.Append(sValue);
sb.Append("%'");
break;
case "DoesNotEndWith":
sb.Append("Not Like '%");
sb.Append(sValue);
sb.Append("'");
break;
case "NotLike":
sb.Append("Not Like '");
sb.Append(sValue);
sb.Append("%'");
break;
default:
throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] IN STRING");
}
break;
case "System.Boolean":
{
switch (sOperator)
{
case "Equals":
sb.Append("= ");
if (sValue == "True")
sb.Append("1");
else
sb.Append("0");
break;
case "NotEquals":
sb.Append("<> ");
if (sValue == "True")
sb.Append("1");
else
sb.Append("0");
break;
default:
throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] in BOOL");
}
}
break;
case "System.Guid":
{
switch (sOperator)
{
case "Equals":
sb.Append("= ");
sb.Append("'");
sb.Append(sValue);
sb.Append("'");
break;
case "NotEquals":
sb.Append("<> ");
sb.Append("'");
sb.Append(sValue);
sb.Append("'");
break;
default:
throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] in BOOL");
}
}
break;
case "System.DateTime":
{
if (sValue.StartsWith("["))
{
#region Build criteria for date RANGE specified
//Used as the basis point
System.DateTime dtAfter;
System.DateTime dtBefore;
switch (sValue)
{
//Case 402
case "[YESTERDAY]":
//Between Day before yesterday at midnight and yesterday at midnight
dtAfter = System.DateTime.Today.AddDays(-1);
dtAfter = dtAfter.AddSeconds(-1);
dtBefore = System.DateTime.Today;//.AddDays(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[TODAY]":
//Between yesterday at midnight and tommorow at midnight
dtAfter = System.DateTime.Today.AddSeconds(-1);
dtBefore = System.DateTime.Today.AddDays(1);
//dtBefore=dtBefore.AddSeconds(1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[TOMORROW]":
//Between Tonight at midnight and day after tommorow at midnight
dtAfter = System.DateTime.Today.AddDays(1);
dtAfter = dtAfter.AddSeconds(-1);
dtBefore = System.DateTime.Today.AddDays(2);
//dtBefore=dtBefore.AddSeconds(1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
//Case 402
case "[LAST WEEK]":
//Between two Sundays ago at midnight and last sunday at midnight
dtAfter = System.DateTime.Today;
//go back a week
dtAfter = dtAfter.AddDays(-7);
//go backwards to Sunday
while (dtAfter.DayOfWeek != DayOfWeek.Sunday)
dtAfter = dtAfter.AddDays(-1);
//go to very start of eighth dayahead
dtBefore = dtAfter.AddDays(8);
dtAfter = dtAfter.AddSeconds(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[THIS WEEK]":
//Between Sunday at midnight and Next sunday at midnight
dtAfter = System.DateTime.Today;
//go backwards to monday
while (dtAfter.DayOfWeek != DayOfWeek.Monday)
dtAfter = dtAfter.AddDays(-1);
//Now go back to sunday last second
dtAfter = dtAfter.AddSeconds(-1);
dtBefore = System.DateTime.Today;
//go forwards to monday
if (System.DateTime.Today.DayOfWeek == DayOfWeek.Monday)
{
//Monday today? then go to next monday
dtBefore = dtBefore.AddDays(7);
}
else
{
while (dtBefore.DayOfWeek != DayOfWeek.Monday)
dtBefore = dtBefore.AddDays(1);
}
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[NEXT WEEK]":
//Between Next Sunday at midnight and Next Next sunday at midnight
dtAfter = System.DateTime.Today;
//If today is monday skip over it first
if (dtAfter.DayOfWeek == DayOfWeek.Monday)
dtAfter = dtAfter.AddDays(1);
//go forwards to next monday
while (dtAfter.DayOfWeek != DayOfWeek.Monday)
dtAfter = dtAfter.AddDays(1);
//Now go back to sunday last second
dtAfter = dtAfter.AddDays(-1);
//go seven days ahead
dtBefore = dtAfter.AddDays(7);
//case 1155
dtAfter = dtAfter.AddSeconds(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[LAST MONTH]":
//start with the first day of this month
dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1, 00, 00, 00);
//subtract a Month
dtAfter = dtAfter.AddMonths(-1);
//Add one month to dtAfter to get end date
dtBefore = dtAfter.AddMonths(1);
//case 1155
dtAfter = dtAfter.AddSeconds(-1);
// 'yyyy-mm-ddTHH:MM:SS'
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[THIS MONTH]":
//start with the first day of this month
dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1, 00, 00, 00);
//Add one month to dtAfter to get end date
dtBefore = dtAfter.AddMonths(1);
//case 1155
dtAfter = dtAfter.AddSeconds(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[NEXT MONTH]":
//start with the first day of this month
dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1, 00, 00, 00);
//Add a Month
dtAfter = dtAfter.AddMonths(1);
//Add one month to dtAfter to get end date
dtBefore = dtAfter.AddMonths(1);
//case 1155
dtAfter = dtAfter.AddSeconds(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[14DAYWINDOW]":
//start with today zero hour
dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 00, 00, 00);
dtAfter = dtAfter.AddDays(-7);
//Add 15 days to get end date (zero hour so not really 15 full days)
dtBefore = dtAfter.AddDays(15);
//case 1155
dtAfter = dtAfter.AddSeconds(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
//case 2067 ADDITIONAL DATE RANGES ************
case "[PAST]":
//Forever up to Now
dtAfter = new DateTime(1753, 1, 2, 00, 00, 00);
dtBefore = System.DateTime.Now;
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[FUTURE]":
//From Now to forever (999 years from now)
dtAfter = System.DateTime.Now;
dtBefore = System.DateTime.Now.AddYears(999);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[LASTYEAR]":
//From zero hour january 1 a year ago
dtAfter = new DateTime(DateTime.Now.AddYears(-1).Year, 1, 1, 00, 00, 00);
//To zero hour January 1 this year
dtBefore = new DateTime(DateTime.Now.Year, 1, 1, 00, 00, 00);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[THISYEAR]":
//From zero hour january 1 this year
dtAfter = new DateTime(DateTime.Now.Year, 1, 1, 00, 00, 00);
//To zero hour Jan 1 next year
dtBefore = new DateTime(DateTime.Now.AddYears(1).Year, 1, 1, 00, 00, 00);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[INTHELAST3MONTHS]":
//From Now minus 3 months
dtAfter = DateTime.Now.AddMonths(-3);
//To Now
dtBefore = DateTime.Now;
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[INTHELAST6MONTHS]":
//From Now minus 6 months
dtAfter = DateTime.Now.AddMonths(-6);
//To Now
dtBefore = DateTime.Now;
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[INTHELASTYEAR]":
//From Now minus 365 days
dtAfter = DateTime.Now.AddDays(-365);
//To Now
dtBefore = DateTime.Now;
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
}
#endregion
}
else
{
#region Build criteria for date specified
//RAVEN NOTE: it is my intention that dates come in iso8601 UTC format from the client
//so a simple parse should be sufficient
//https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings#Roundtrip
System.DateTime dtData = DateTime.Parse(sValue);
//RAVEN NOTE: there is some old code kept commented out for now as I'm not certain I need the high low stuff anymore
// sValue = dtData.ToString(SqlDateFormatHighLow(false));
// string sHighEnd = dtData.ToString(SqlDateFormatHighLow(true));
// string sLowEnd = dtData.ToString(SqlDateFormatHighLow(false));
// string sGreaterThanValue = dtData.AddSeconds(1).ToString(SqlDateFormatHighLow(false));
// string sLessThanValue = dtData.AddSeconds(-1).ToString(SqlDateFormatHighLow(true));
sValue = PostgresDateFormat(ZeroMilliseconds(dtData));
string sHighEnd = PostgresDateFormat(MaxMilliseconds(dtData));
string sLowEnd = PostgresDateFormat(ZeroMilliseconds(dtData));
string sGreaterThanValue = PostgresDateFormat(ZeroMilliseconds(dtData.AddSeconds(1)));
string sLessThanValue = PostgresDateFormat(MaxMilliseconds(dtData.AddSeconds(-1)));
switch (sOperator)
{
//case "Equals":
// sb.Append("='");
// sb.Append(sValue);
// sb.Append("'");
// break;
case "Equals":
sb.Append(">='");
sb.Append(sLowEnd);
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<='");
sb.Append(sHighEnd);
sb.Append("'");
break;
case "GreaterThan":
sb.Append(">'");
sb.Append(sGreaterThanValue);
sb.Append("'");
break;
case "GreaterThanOrEqualTo":
sb.Append(">='");
sb.Append(sLowEnd);
sb.Append("'");
break;
case "LessThan":
sb.Append("<'");
sb.Append(sLessThanValue);
sb.Append("'");
break;
case "LessThanOrEqualTo":
sb.Append("<='");
sb.Append(sHighEnd);
sb.Append("'");
break;
//case "NotEquals":
// sb.Append("<>'");
// sb.Append(sValue);
// sb.Append("'");
// break;
case "NotEquals":
sb.Append("<'");
sb.Append(sLowEnd);
sb.Append("') OR (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append(">'");
sb.Append(sHighEnd);
sb.Append("'");
break;
default:
throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] IN DATE_TIME");
}
#endregion
}
}
break;
case "System.Decimal":
case "System.Int32":
case "System.Int64"://case 808
{
//case 1795 - it's numeric, convert to locale independant format
NumberFormatInfo nfi = System.Globalization.CultureInfo.CurrentCulture.NumberFormat;
switch (sDataType)
{
case "System.Decimal":
{
if (nfi.CurrencyDecimalSeparator != ".")
{
sValue = sValue.Replace(nfi.CurrencyGroupSeparator, "");
sValue = sValue.Replace(nfi.CurrencyDecimalSeparator, ".");
}
}
break;
case "System.Int32":
{
if (nfi.NumberDecimalSeparator != ".")
{
sValue = sValue.Replace(nfi.NumberGroupSeparator, "");
sValue = sValue.Replace(nfi.NumberDecimalSeparator, ".");
}
}
break;
case "System.Int64":
{
if (nfi.NumberDecimalSeparator != ".")
{
sValue = sValue.Replace(nfi.NumberGroupSeparator, "");
sValue = sValue.Replace(nfi.NumberDecimalSeparator, ".");
}
}
break;
}
switch (sOperator)
{
case "Equals":
sb.Append("=");
sb.Append(sValue);
break;
case "GreaterThan":
sb.Append(">");
sb.Append(sValue);
break;
case "GreaterThanOrEqualTo":
sb.Append(">=");
sb.Append(sValue);
break;
case "LessThan":
sb.Append("<");
sb.Append(sValue);
break;
case "LessThanOrEqualTo":
sb.Append("<=");
sb.Append(sValue);
break;
// case "Like":
// sb.Append("Like N'");
// sb.Append(sValue);
// sb.Append("%'");
// break;
case "NotEquals":
sb.Append("<>");
sb.Append(sValue);
break;
default:
throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] IN DECIMAL");
}
break;
}
default:
throw new System.ArgumentOutOfRangeException("DATA_TYPE", sDataType, "GridToSqlCriteria unhandled data type[" + sDataType + "]");
}
#endregion
}
//
//if(log.IsDebugEnabled)
// //case 1039 //log.Debug("GridToSqlCriteria: returning[" + sb.ToString() + "]");
return sb.ToString();
}
// public static string SqlDateFormatHighLow(bool bhigh)
// {
// //new test version
// if (bhigh)
// return SqlDateFormat() + ".999";
// else
// return SqlDateFormat() + ".000";
// }
public static DateTime ZeroMilliseconds(DateTime d)
{
if (d.Millisecond == 0) return d;
return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second, DateTimeKind.Utc);
}
public static DateTime MaxMilliseconds(DateTime d)
{
if (d.Millisecond == 0) return d;
return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second, 999, DateTimeKind.Utc);
}
/// <summary>
/// Postgres compatible date format
/// https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-DATETIME-DATE-TABLE
/// </summary>
/// <returns></returns>
public static string PostgresDateFormat(DateTime theDate)
{
//If this was used it should be like this for a UTC date to iso8601
// ISO8601 with 7 decimal places
return theDate.ToString("o", CultureInfo.InvariantCulture);
// if (DBUtil.DB.DBType == DataBaseType.MSSQL)
// return "yyyy-MM-ddTHH:mm:ss";
// else
// return "yyyy-MM-dd HH:mm:ss";
}
}//eoc
}//ens