From aeeaf0bf30c3e06963a00c142eabb027b4d311be Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Fri, 30 Nov 2018 23:48:05 +0000 Subject: [PATCH] --- ...-list-graph-datatable-filtering-paging.txt | 6 +- devdocs/todo.txt | 2 +- .../AyaNova/biz/FilterSqlCriteriaBuilder.cs | 851 ++++++++++++++++++ 3 files changed, 856 insertions(+), 3 deletions(-) create mode 100644 server/AyaNova/biz/FilterSqlCriteriaBuilder.cs diff --git a/devdocs/specs/core-list-graph-datatable-filtering-paging.txt b/devdocs/specs/core-list-graph-datatable-filtering-paging.txt index 0fa67c0c..96ff6e4c 100644 --- a/devdocs/specs/core-list-graph-datatable-filtering-paging.txt +++ b/devdocs/specs/core-list-graph-datatable-filtering-paging.txt @@ -27,7 +27,7 @@ Filters are saved to the database: - op=one of the values specified in the FilterComparisonOperator class in Biz namespace - value= straight up direct comparison value - If string then a string fragment, case is sensitive - - If date then iso style date + - If date then iso style date //RAVEN NOTE: it is my intention that dates come in iso8601 UTC format from the client - could be whole number or decimal number - Could be a special "macro" filter value like "[THIS_MONTH]" (always surrounded by square brackets, no need to disambiguate with a string because only applies to non string values) - Could be a series of id values like this "[23,45,56,123]" as in tag id's or something related to that case. @@ -59,10 +59,12 @@ NOTES ABOUT WHY I DID THE FILTEROPTIONS LIKE I DID: LIST FILTERING TODO - DONE test for fetching widget filter options (localized, so have two users test each for expected response) - Add test for excercising all of DataFilterController route including rights to non personal alternative owner etc -Add test for correctly validated Widget datafilter when saved or updated via datafiltercontroller (sanity check of the filter settings and options IFilterableObject implemented) + - Add test for correctly validated Widget datafilter when saved or updated via datafiltercontroller (sanity check of the filter settings and options IFilterableObject implemented) Add test for providing saved filter id to widgetlist and recieving correct filtered / paged / sorted results (test all those) - Requires filter to sql code to be written and changes to the widgetlist route + - This is where it gets real! Happy monday!! :) + - Copy as much from v7 as possible - Client side - Implement filter editor dialog and test diff --git a/devdocs/todo.txt b/devdocs/todo.txt index ab9e16ed..07f7ed97 100644 --- a/devdocs/todo.txt +++ b/devdocs/todo.txt @@ -5,7 +5,7 @@ Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNTQyNjY5Njc3IiwiZXhwIjoi ## IMMEDIATE ITEMS -filtering test see core-list-graph-datatable-filtering-paging.txt doc +filter to SQL / Widget list filtered with tests - see core-list-graph-datatable-filtering-paging.txt doc SERVER SCHEMA - Add unique constraint to all name columns in all tables in ayschema and run tests (how did I miss that before??) diff --git a/server/AyaNova/biz/FilterSqlCriteriaBuilder.cs b/server/AyaNova/biz/FilterSqlCriteriaBuilder.cs new file mode 100644 index 00000000..25adedd6 --- /dev/null +++ b/server/AyaNova/biz/FilterSqlCriteriaBuilder.cs @@ -0,0 +1,851 @@ +using System.Collections.Generic; +using System; +using System.Globalization; +using System.Text; + +namespace AyaNova.Biz +{ + public static class FilterSqlCriteriaBuilder + { + + /// + /// Used internally by AyaNova UI to translate Infragistics grid filter settings to AyaNova friendly SQL critiera + /// + 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("&", "&"); + + 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); + } + + /// + /// Postgres compatible date format + /// https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-DATETIME-DATE-TABLE + /// + /// + 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