diff --git a/FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs index 62d242ee8..eb3ebb16a 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs @@ -10,158 +10,158 @@ [ExpressionCall] public static class FreeSqlGlobalExpressionCallExtensions { - public static ThreadLocal expContext = new ThreadLocal(); + public static ThreadLocal expContext = new ThreadLocal(); - /// - /// C#: that >= between && that <= and - /// SQL: that BETWEEN between AND and - /// - /// - /// - /// - /// - public static bool Between(this DateTime that, DateTime between, DateTime and) - { - if (expContext.IsValueCreated == false || expContext.Value == null || expContext.Value.ParsedContent == null) - return that >= between && that <= and; - var time1 = expContext.Value.RawExpression["between"].IsParameter() == false ? - expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["between"]).Compile().DynamicInvoke()) : - expContext.Value.ParsedContent["between"]; - var time2 = expContext.Value.RawExpression["and"].IsParameter() == false ? - expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["and"]).Compile().DynamicInvoke()) : - expContext.Value.ParsedContent["and"]; - expContext.Value.Result = $"{expContext.Value.ParsedContent["that"]} between {time1} and {time2}"; - return false; - } + /// + /// C#: that >= between && that <= and + /// SQL: that BETWEEN between AND and + /// + /// + /// + /// + /// + public static bool Between(this DateTime that, DateTime between, DateTime and) + { + if (expContext.IsValueCreated == false || expContext.Value == null || expContext.Value.ParsedContent == null) + return that >= between && that <= and; + var time1 = expContext.Value.RawExpression["between"].IsParameter() == false ? + expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["between"]).Compile().DynamicInvoke()) : + expContext.Value.ParsedContent["between"]; + var time2 = expContext.Value.RawExpression["and"].IsParameter() == false ? + expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["and"]).Compile().DynamicInvoke()) : + expContext.Value.ParsedContent["and"]; + expContext.Value.Result = $"{expContext.Value.ParsedContent["that"]} between {time1} and {time2}"; + return false; + } - /// - /// 注意:这个方法和 Between 有细微区别 - /// C#: that >= start && that < end - /// SQL: that >= start and that < end - /// - /// - /// - /// - /// - public static bool BetweenEnd(this DateTime that, DateTime start, DateTime end) - { - if (expContext.IsValueCreated == false || expContext.Value == null || expContext.Value.ParsedContent == null) - return that >= start && that < end; - var time1 = expContext.Value.RawExpression["start"].IsParameter() == false ? - expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["start"]).Compile().DynamicInvoke()) : - expContext.Value.ParsedContent["start"]; - var time2 = expContext.Value.RawExpression["end"].IsParameter() == false ? - expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["end"]).Compile().DynamicInvoke()) : - expContext.Value.ParsedContent["end"]; - expContext.Value.Result = $"{expContext.Value.ParsedContent["that"]} >= {time1} and {expContext.Value.ParsedContent["that"]} < {time2}"; - return false; - } + /// + /// 注意:这个方法和 Between 有细微区别 + /// C#: that >= start && that < end + /// SQL: that >= start and that < end + /// + /// + /// + /// + /// + public static bool BetweenEnd(this DateTime that, DateTime start, DateTime end) + { + if (expContext.IsValueCreated == false || expContext.Value == null || expContext.Value.ParsedContent == null) + return that >= start && that < end; + var time1 = expContext.Value.RawExpression["start"].IsParameter() == false ? + expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["start"]).Compile().DynamicInvoke()) : + expContext.Value.ParsedContent["start"]; + var time2 = expContext.Value.RawExpression["end"].IsParameter() == false ? + expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["end"]).Compile().DynamicInvoke()) : + expContext.Value.ParsedContent["end"]; + expContext.Value.Result = $"{expContext.Value.ParsedContent["that"]} >= {time1} and {expContext.Value.ParsedContent["that"]} < {time2}"; + return false; + } } namespace FreeSql { - /// - /// SqlExt 是利用自定表达式函数解析功能,解析默认常用的SQL函数,欢迎 PR - /// - [ExpressionCall] - public static class SqlExt - { - internal static ThreadLocal expContext = new ThreadLocal(); + /// + /// SqlExt 是利用自定表达式函数解析功能,解析默认常用的SQL函数,欢迎 PR + /// + [ExpressionCall] + public static class SqlExt + { + internal static ThreadLocal expContext = new ThreadLocal(); - //public static bool BitAnd(TEnum enum1, [RawValue] TEnum enum2) - //{ - // expContext.Value.Result = $"({expContext.Value.ParsedContent["enum1"]} & {Convert.ToInt32(enum2)}) = {Convert.ToInt32(enum2)}"; - // return false; - //} - //public static bool BitOr(TEnum enum1, [RawValue] TEnum enum2) - //{ - // expContext.Value.Result = $"({expContext.Value.ParsedContent["enum1"]} | {Convert.ToInt32(enum2)}) = {Convert.ToInt32(enum2)}"; - // return false; - //} + //public static bool BitAnd(TEnum enum1, [RawValue] TEnum enum2) + //{ + // expContext.Value.Result = $"({expContext.Value.ParsedContent["enum1"]} & {Convert.ToInt32(enum2)}) = {Convert.ToInt32(enum2)}"; + // return false; + //} + //public static bool BitOr(TEnum enum1, [RawValue] TEnum enum2) + //{ + // expContext.Value.Result = $"({expContext.Value.ParsedContent["enum1"]} | {Convert.ToInt32(enum2)}) = {Convert.ToInt32(enum2)}"; + // return false; + //} - #region SqlServer/PostgreSQL over - /// - /// rank() over(order by ...) - /// - /// - public static ISqlOver Rank() => Over("rank()"); - /// - /// dense_rank() over(order by ...) - /// - /// - public static ISqlOver DenseRank() => Over("dense_rank()"); - /// - /// count() over(order by ...) - /// - /// - public static ISqlOver Count(object column) => Over($"count({expContext.Value.ParsedContent["column"]})"); - /// - /// sum(..) over(order by ...) - /// - /// - /// - public static ISqlOver Sum(object column) => Over($"sum({expContext.Value.ParsedContent["column"]})"); - /// - /// avg(..) over(order by ...) - /// - /// - public static ISqlOver Avg(object column) => Over($"avg({expContext.Value.ParsedContent["column"]})"); - /// - /// max(..) over(order by ...) - /// - /// - /// - /// - public static ISqlOver Max(T column) => Over($"max({expContext.Value.ParsedContent["column"]})"); - /// - /// min(..) over(order by ...) - /// - /// - /// - /// - public static ISqlOver Min(T column) => Over($"min({expContext.Value.ParsedContent["column"]})"); - /// - /// SqlServer row_number() over(order by ...) - /// - /// - public static ISqlOver RowNumber() => Over("row_number()"); - #endregion + #region SqlServer/PostgreSQL over + /// + /// rank() over(order by ...) + /// + /// + public static ISqlOver Rank() => Over("rank()"); + /// + /// dense_rank() over(order by ...) + /// + /// + public static ISqlOver DenseRank() => Over("dense_rank()"); + /// + /// count() over(order by ...) + /// + /// + public static ISqlOver Count(object column) => Over($"count({expContext.Value.ParsedContent["column"]})"); + /// + /// sum(..) over(order by ...) + /// + /// + /// + public static ISqlOver Sum(object column) => Over($"sum({expContext.Value.ParsedContent["column"]})"); + /// + /// avg(..) over(order by ...) + /// + /// + public static ISqlOver Avg(object column) => Over($"avg({expContext.Value.ParsedContent["column"]})"); + /// + /// max(..) over(order by ...) + /// + /// + /// + /// + public static ISqlOver Max(T column) => Over($"max({expContext.Value.ParsedContent["column"]})"); + /// + /// min(..) over(order by ...) + /// + /// + /// + /// + public static ISqlOver Min(T column) => Over($"min({expContext.Value.ParsedContent["column"]})"); + /// + /// SqlServer row_number() over(order by ...) + /// + /// + public static ISqlOver RowNumber() => Over("row_number()"); + #endregion - /// - /// isnull、ifnull、coalesce、nvl - /// - /// - /// - /// - /// - public static TValue IsNull(TValue value, TValue defaultValue) - { - expContext.Value.Result = expContext.Value._commonExp._common.IsNull(expContext.Value.ParsedContent["value"], expContext.Value.ParsedContent["defaultValue"]); - return default(TValue); - } + /// + /// isnull、ifnull、coalesce、nvl + /// + /// + /// + /// + /// + public static TValue IsNull(TValue value, TValue defaultValue) + { + expContext.Value.Result = expContext.Value._commonExp._common.IsNull(expContext.Value.ParsedContent["value"], expContext.Value.ParsedContent["defaultValue"]); + return default(TValue); + } - /// - /// count(distinct name) - /// - /// - /// - /// - public static long DistinctCount(T column) - { - expContext.Value.Result = $"count(distinct {expContext.Value.ParsedContent["column"]})"; - return 0; - } + /// + /// count(distinct name) + /// + /// + /// + /// + public static long DistinctCount(T column) + { + expContext.Value.Result = $"count(distinct {expContext.Value.ParsedContent["column"]})"; + return 0; + } - /// - /// 注意:使用者自己承担【注入风险】 - /// - /// - /// - static bool InternalRawSql([RawValue] string sql) - { - expContext.Value.Result = sql; - return false; - } + /// + /// 注意:使用者自己承担【注入风险】 + /// + /// + /// + static bool InternalRawSql([RawValue] string sql) + { + expContext.Value.Result = sql; + return false; + } static object InternalRawField([RawValue] string sql) { expContext.Value.Result = sql; @@ -174,340 +174,396 @@ static object InternalRawField([RawValue] string sql) /// /// public static bool GreaterThan(TValue value1, TValue value2) - { - expContext.Value.Result = $"{expContext.Value.ParsedContent["value1"]} > {expContext.Value.ParsedContent["value2"]}"; - return false; - } - /// - /// 大于或等于 >= - /// - /// - public static bool GreaterThanOrEqual(TValue value1, TValue value2) - { - expContext.Value.Result = $"{expContext.Value.ParsedContent["value1"]} >= {expContext.Value.ParsedContent["value2"]}"; - return false; - } - /// - /// 小于 < - /// - /// - public static bool LessThan(TValue value1, TValue value2) - { - expContext.Value.Result = $"{expContext.Value.ParsedContent["value1"]} < {expContext.Value.ParsedContent["value2"]}"; - return false; - } - /// - /// 小于或等于 <= - /// - /// - public static bool LessThanOrEqual(TValue value1, TValue value2) - { - expContext.Value.Result = $"{expContext.Value.ParsedContent["value1"]} <= {expContext.Value.ParsedContent["value2"]}"; - return false; - } - /// - /// value1 IS NULL - /// - /// - /// - /// - public static bool EqualIsNull(TValue value1) - { - expContext.Value.Result = $"{expContext.Value.ParsedContent["value1"]} IS NULL"; - return false; - } - #endregion + { + expContext.Value.Result = $"{expContext.Value.ParsedContent["value1"]} > {expContext.Value.ParsedContent["value2"]}"; + return false; + } + /// + /// 大于或等于 >= + /// + /// + public static bool GreaterThanOrEqual(TValue value1, TValue value2) + { + expContext.Value.Result = $"{expContext.Value.ParsedContent["value1"]} >= {expContext.Value.ParsedContent["value2"]}"; + return false; + } + /// + /// 小于 < + /// + /// + public static bool LessThan(TValue value1, TValue value2) + { + expContext.Value.Result = $"{expContext.Value.ParsedContent["value1"]} < {expContext.Value.ParsedContent["value2"]}"; + return false; + } + /// + /// 小于或等于 <= + /// + /// + public static bool LessThanOrEqual(TValue value1, TValue value2) + { + expContext.Value.Result = $"{expContext.Value.ParsedContent["value1"]} <= {expContext.Value.ParsedContent["value2"]}"; + return false; + } + /// + /// value1 IS NULL + /// + /// + /// + /// + public static bool EqualIsNull(TValue value1) + { + expContext.Value.Result = $"{expContext.Value.ParsedContent["value1"]} IS NULL"; + return false; + } + #endregion + + #region 时间比较 + /// + /// 计算两个日期之间的差异 + /// 时间2 - 时间1 + /// + /// + /// + /// + public static long DateDiff(string datePart, DateTimeOffset dateTimeOffset1, DateTimeOffset dateTimeOffset2) + { + var up = expContext.Value; + + // 根据不同数据库类型定义不同的 SQL 语句 + if (up.DataType == DataType.SqlServer) + { + up.Result = $"DATEDIFF({datePart}, {up.ParsedContent["dateTimeOffset1"]}, {up.ParsedContent["dateTimeOffset2"]})"; + } + else if (up.DataType == DataType.MySql) + { + up.Result = $"TIMESTAMPDIFF({datePart}, {up.ParsedContent["dateTimeOffset1"]}, {up.ParsedContent["dateTimeOffset2"]})"; + } + else + { + throw new NotImplementedException("不支持的数据库类型"); + } + return 0; + } + /// + /// 计算两个日期之间的差异 + /// 时间2 - 时间1 + /// + /// + /// 时间1 + /// 时间2 + public static long DateDiff(string datePart, DateTime dateTime1, DateTime dateTime2) + { + var up = expContext.Value; - /// - /// case when .. then .. end - /// - /// - public static ICaseWhenEnd Case() => SqlExtExtensions.Case(); - /// - /// case when .. then .. end - /// - /// - /// - /// - /// - /// - public static TOutput CaseDict(TInput input, [RawValue] Dictionary dict) - { - var ec = expContext.Value; - var sb = new StringBuilder(); - sb.Append("case"); - foreach (var kv in dict) - sb.Append(" when ").Append(ec.ParsedContent["input"]).Append(" = ").Append(ec.FormatSql(kv.Key)) - .Append(" then ").Append(ec.FormatSql(kv.Value)); - sb.Append(" end"); - ec.Result = sb.ToString(); - return default; - } - /// - /// MySql group_concat(distinct .. order by .. separator ..) - /// - /// - /// - public static IGroupConcat GroupConcat(object column) => SqlExtExtensions.GroupConcat(column); - /// - /// MySql find_in_set(str, strlist) - /// - /// - /// - /// - /// - public static int FindInSet(TValue str, string strlist) - { - expContext.Value.Result = $"find_in_set({expContext.Value.ParsedContent["str"]}, {expContext.Value.ParsedContent["strlist"]})"; - return 0; - } + // 根据不同数据库类型定义不同的 SQL 语句 + if (up.DataType == DataType.SqlServer) + { + up.Result = $"DATEDIFF({datePart}, {up.ParsedContent["dateTimeOffset1"]}, {up.ParsedContent["dateTimeOffset2"]})"; + } + else if (up.DataType == DataType.MySql) + { + up.Result = $"TIMESTAMPDIFF({datePart}, {up.ParsedContent["dateTimeOffset1"]}, {up.ParsedContent["dateTimeOffset2"]})"; + } + else + { + throw new NotImplementedException("不支持的数据库类型"); + } + return 0; + } + #endregion - /// - /// PostgreSQL string_agg(.., ..) - /// - /// - /// - /// - public static string StringAgg(object column, object delimiter) - { - expContext.Value.Result = $"string_agg({expContext.Value.ParsedContent["column"]}, {expContext.Value.ParsedContent["delimiter"]})"; - return ""; - } - } + /// + /// case when .. then .. end + /// + /// + public static ICaseWhenEnd Case() => SqlExtExtensions.Case(); + /// + /// case when .. then .. end + /// + /// + /// + /// + /// + /// + public static TOutput CaseDict(TInput input, [RawValue] Dictionary dict) + { + var ec = expContext.Value; + var sb = new StringBuilder(); + sb.Append("case"); + foreach (var kv in dict) + sb.Append(" when ").Append(ec.ParsedContent["input"]).Append(" = ").Append(ec.FormatSql(kv.Key)) + .Append(" then ").Append(ec.FormatSql(kv.Value)); + sb.Append(" end"); + ec.Result = sb.ToString(); + return default; + } + /// + /// MySql group_concat(distinct .. order by .. separator ..) + /// + /// + /// + public static IGroupConcat GroupConcat(object column) => SqlExtExtensions.GroupConcat(column); + /// + /// MySql find_in_set(str, strlist) + /// + /// + /// + /// + /// + public static int FindInSet(TValue str, string strlist) + { + expContext.Value.Result = $"find_in_set({expContext.Value.ParsedContent["str"]}, {expContext.Value.ParsedContent["strlist"]})"; + return 0; + } - [ExpressionCall] - public static class SqlExtExtensions //这个类存在的意义,是不想使用者方法名污染 - { - static ThreadLocal expContextSelf = new ThreadLocal(); - static ExpressionCallContext expContext => expContextSelf.Value ?? SqlExt.expContext.Value; - internal static ThreadLocal> expSb = new ThreadLocal>(); - internal static ExpSbInfo expSbLast => expSb.Value.Last(); - internal class ExpSbInfo - { - public StringBuilder Sb { get; } = new StringBuilder(); - public bool IsOver = false; - public bool IsOrderBy = false; - public bool IsDistinct = false; - } + /// + /// PostgreSQL string_agg(.., ..) + /// + /// + /// + /// + public static string StringAgg(object column, object delimiter) + { + expContext.Value.Result = $"string_agg({expContext.Value.ParsedContent["column"]}, {expContext.Value.ParsedContent["delimiter"]})"; + return ""; + } + } - #region .. over([partition by ..] order by ...) - internal static ISqlOver Over(string sqlFunc) - { - if (expSb.Value == null) expSb.Value = new List(); - expSb.Value.Add(new ExpSbInfo()); - expSbLast.Sb.Append(sqlFunc); - return null; - } - public static ISqlOver Over(this ISqlOver that) - { - expSbLast.Sb.Append(" over("); - expSbLast.IsOver = true; - return that; - } - public static ISqlOver PartitionBy(this ISqlOver that, object column) - { - var sb = expSbLast.Sb; - sb.Append(" partition by "); - var exp = expContext.RawExpression["column"]; - if (exp.NodeType == ExpressionType.New) - { - var expNew = exp as NewExpression; - for (var a = 0; a < expNew.Arguments.Count; a++) - { - if (a > 0) sb.Append(","); - sb.Append(expContext.Utility.ParseExpression(expNew.Arguments[a])); - } - } else - sb.Append(expContext.ParsedContent["column"]); - return that; - } - public static ISqlOver OrderBy(this ISqlOver that, object column) => OrderByPriv(that, false); - public static ISqlOver OrderByDescending(this ISqlOver that, object column) => OrderByPriv(that, true); - static ISqlOver OrderByPriv(this ISqlOver that, bool isDesc) - { - var sb = expSbLast.Sb; - if (expSbLast.IsOrderBy == false) - { - sb.Append(" order by "); - expSbLast.IsOrderBy = true; - } - var exp = expContext.RawExpression["column"]; - if (exp.NodeType == ExpressionType.New) - { - var expNew = exp as NewExpression; - for (var a = 0; a < expNew.Arguments.Count; a++) - { - sb.Append(expContext.Utility.ParseExpression(expNew.Arguments[a])); - if (isDesc) sb.Append(" desc"); - sb.Append(","); - } - } - else - { - sb.Append(expContext.ParsedContent["column"]); - if (isDesc) sb.Append(" desc"); - sb.Append(","); - } - return that; - } - public static TValue ToValue(this ISqlOver that) - { - var sql = expSbLast.Sb.ToString().TrimEnd(','); - if (expSbLast.IsOver) sql = $"{sql})"; - expSbLast.Sb.Clear(); - expSb.Value.RemoveAt(expSb.Value.Count - 1); - expContext.Result = sql; - return default; - } - public interface ISqlOver { } - #endregion + [ExpressionCall] + public static class SqlExtExtensions //这个类存在的意义,是不想使用者方法名污染 + { + static ThreadLocal expContextSelf = new ThreadLocal(); + static ExpressionCallContext expContext => expContextSelf.Value ?? SqlExt.expContext.Value; + internal static ThreadLocal> expSb = new ThreadLocal>(); + internal static ExpSbInfo expSbLast => expSb.Value.Last(); + internal class ExpSbInfo + { + public StringBuilder Sb { get; } = new StringBuilder(); + public bool IsOver = false; + public bool IsOrderBy = false; + public bool IsDistinct = false; + } - #region case when .. then .. when .. then .. end - public static ICaseWhenEnd Case() - { - if (expSb.Value == null) expSb.Value = new List(); - expSb.Value.Add(new ExpSbInfo()); - expSbLast.Sb.Append("case "); - return null; - } - public static ICaseWhenEnd When(this ICaseWhenEnd that, bool test, TValue then) - { - expSbLast.Sb.Append($"\r\n{"".PadRight(expSb.Value.Count * 2)}when ").Append(expContext.ParsedContent["test"]).Append(" then ").Append(expContext.ParsedContent["then"]); - return null; - } - public static ICaseWhenEnd When(this ICaseWhenEnd that, bool test, TValue then) - { - expSbLast.Sb.Append($"\r\n{"".PadRight(expSb.Value.Count * 2)}when ").Append(expContext.ParsedContent["test"]).Append(" then ").Append(expContext.ParsedContent["then"]); - return null; - } - public static ICaseWhenEnd Else(this ICaseWhenEnd that, TValue then) - { - expSbLast.Sb.Append($"\r\n{"".PadRight(expSb.Value.Count * 2)}else ").Append(expContext.ParsedContent["then"]); - return null; - } - public static TValue End(this ICaseWhenEnd that) - { - var sql = expSbLast.Sb.Append($"\r\n{"".PadRight(expSb.Value.Count * 2 - 2)}end").ToString(); - expSbLast.Sb.Clear(); - expSb.Value.RemoveAt(expSb.Value.Count - 1); - expContext.Result = sql; - return default; - } - public interface ICaseWhenEnd { } - public interface ICaseWhenEnd { } - #endregion + #region .. over([partition by ..] order by ...) + internal static ISqlOver Over(string sqlFunc) + { + if (expSb.Value == null) expSb.Value = new List(); + expSb.Value.Add(new ExpSbInfo()); + expSbLast.Sb.Append(sqlFunc); + return null; + } + public static ISqlOver Over(this ISqlOver that) + { + expSbLast.Sb.Append(" over("); + expSbLast.IsOver = true; + return that; + } + public static ISqlOver PartitionBy(this ISqlOver that, object column) + { + var sb = expSbLast.Sb; + sb.Append(" partition by "); + var exp = expContext.RawExpression["column"]; + if (exp.NodeType == ExpressionType.New) + { + var expNew = exp as NewExpression; + for (var a = 0; a < expNew.Arguments.Count; a++) + { + if (a > 0) sb.Append(","); + sb.Append(expContext.Utility.ParseExpression(expNew.Arguments[a])); + } + } + else + sb.Append(expContext.ParsedContent["column"]); + return that; + } + public static ISqlOver OrderBy(this ISqlOver that, object column) => OrderByPriv(that, false); + public static ISqlOver OrderByDescending(this ISqlOver that, object column) => OrderByPriv(that, true); + static ISqlOver OrderByPriv(this ISqlOver that, bool isDesc) + { + var sb = expSbLast.Sb; + if (expSbLast.IsOrderBy == false) + { + sb.Append(" order by "); + expSbLast.IsOrderBy = true; + } + var exp = expContext.RawExpression["column"]; + if (exp.NodeType == ExpressionType.New) + { + var expNew = exp as NewExpression; + for (var a = 0; a < expNew.Arguments.Count; a++) + { + sb.Append(expContext.Utility.ParseExpression(expNew.Arguments[a])); + if (isDesc) sb.Append(" desc"); + sb.Append(","); + } + } + else + { + sb.Append(expContext.ParsedContent["column"]); + if (isDesc) sb.Append(" desc"); + sb.Append(","); + } + return that; + } + public static TValue ToValue(this ISqlOver that) + { + var sql = expSbLast.Sb.ToString().TrimEnd(','); + if (expSbLast.IsOver) sql = $"{sql})"; + expSbLast.Sb.Clear(); + expSb.Value.RemoveAt(expSb.Value.Count - 1); + expContext.Result = sql; + return default; + } + public interface ISqlOver { } + #endregion - #region group_concat - public static IGroupConcat GroupConcat(object column) - { - if (expSb.Value == null) expSb.Value = new List(); - expSb.Value.Add(new ExpSbInfo()); - expSbLast.Sb.Append("group_concat(").Append(expContext.ParsedContent["column"]); - return null; - } - public static IGroupConcat Distinct(this IGroupConcat that) - { - if (expSbLast.IsDistinct == false) - { - expSbLast.Sb.Insert(expSbLast.Sb.ToString().LastIndexOf("group_concat(") + 13, "distinct "); - expSbLast.IsDistinct = true; - } - return that; - } - public static IGroupConcat Separator(this IGroupConcat that, object separator) - { - if (expSbLast.IsOrderBy) expSbLast.Sb.Remove(expSbLast.Sb.Length - 1, 1); - expSbLast.Sb.Append(" separator ").Append(expContext.ParsedContent["separator"]); - return that; - } - public static IGroupConcat OrderBy(this IGroupConcat that, object column) => OrderByPriv(that, false); - public static IGroupConcat OrderByDescending(this IGroupConcat that, object column) => OrderByPriv(that, true); - static IGroupConcat OrderByPriv(this IGroupConcat that, bool isDesc) - { - var sb = expSbLast.Sb; - if (expSbLast.IsOrderBy == false) - { - sb.Append(" order by "); - expSbLast.IsOrderBy = true; - } - var exp = expContext.RawExpression["column"]; - if (exp.NodeType == ExpressionType.New) - { - var expNew = exp as NewExpression; - for (var a = 0; a < expNew.Arguments.Count; a++) - { - sb.Append(expContext.Utility.ParseExpression(expNew.Arguments[a])); - if (isDesc) sb.Append(" desc"); - sb.Append(","); - } - } - else - { - sb.Append(expContext.ParsedContent["column"]); - if (isDesc) sb.Append(" desc"); - sb.Append(","); - } - return that; - } - public static string ToValue(this IGroupConcat that) - { - var sql = expSbLast.Sb.ToString().TrimEnd(','); - expSbLast.Sb.Clear(); - expSb.Value.RemoveAt(expSb.Value.Count - 1); - expContext.Result = $"{sql})"; - return default; - } - public interface IGroupConcat { } - #endregion + #region case when .. then .. when .. then .. end + public static ICaseWhenEnd Case() + { + if (expSb.Value == null) expSb.Value = new List(); + expSb.Value.Add(new ExpSbInfo()); + expSbLast.Sb.Append("case "); + return null; + } + public static ICaseWhenEnd When(this ICaseWhenEnd that, bool test, TValue then) + { + expSbLast.Sb.Append($"\r\n{"".PadRight(expSb.Value.Count * 2)}when ").Append(expContext.ParsedContent["test"]).Append(" then ").Append(expContext.ParsedContent["then"]); + return null; + } + public static ICaseWhenEnd When(this ICaseWhenEnd that, bool test, TValue then) + { + expSbLast.Sb.Append($"\r\n{"".PadRight(expSb.Value.Count * 2)}when ").Append(expContext.ParsedContent["test"]).Append(" then ").Append(expContext.ParsedContent["then"]); + return null; + } + public static ICaseWhenEnd Else(this ICaseWhenEnd that, TValue then) + { + expSbLast.Sb.Append($"\r\n{"".PadRight(expSb.Value.Count * 2)}else ").Append(expContext.ParsedContent["then"]); + return null; + } + public static TValue End(this ICaseWhenEnd that) + { + var sql = expSbLast.Sb.Append($"\r\n{"".PadRight(expSb.Value.Count * 2 - 2)}end").ToString(); + expSbLast.Sb.Clear(); + expSb.Value.RemoveAt(expSb.Value.Count - 1); + expContext.Result = sql; + return default; + } + public interface ICaseWhenEnd { } + public interface ICaseWhenEnd { } + #endregion - #region string.Join 反射处理,此块代码用于反射,所以别修改定义 - public static string StringJoinSqliteGroupConcat(object column, object delimiter) - { - expContext.Result = $"group_concat({expContext.ParsedContent["column"]},{expContext.ParsedContent["delimiter"]})"; - return null; - } - public static string StringJoinPgsqlGroupConcat(object column, object delimiter) - { - expContext.Result = $"string_agg(({expContext.ParsedContent["column"]})::text,{expContext.ParsedContent["delimiter"]})"; - return null; - } - public static string StringJoinMySqlGroupConcat(object column, object delimiter) - { - expContext.Result = $"group_concat({expContext.ParsedContent["column"]} separator {expContext.ParsedContent["delimiter"]})"; - return null; - } - public static string StringJoinOracleGroupConcat(object column, object delimiter) - { - string orderby = null; - var subSelect = expContext._tsc?.subSelect001; - if (subSelect != null) - { - orderby = subSelect?._orderby?.Trim('\r', '\n'); - if (string.IsNullOrEmpty(orderby)) - { - var subSelectTb1 = subSelect._tables.FirstOrDefault(); - if (subSelectTb1 != null && subSelectTb1.Table.Primarys.Any() == true) - orderby = $"order by {string.Join(",", subSelectTb1.Table.Primarys.Select(a => $"{subSelectTb1.Alias}.{subSelect._commonUtils.QuoteSqlName(a.Attribute.Name)}"))}"; - } - } - if (string.IsNullOrEmpty(orderby)) orderby = "order by 1"; - expContext.Result = $"listagg(to_char({expContext.ParsedContent["column"]}),{expContext.ParsedContent["delimiter"]}) within group({orderby})"; - return null; - } - public static string StringJoinFirebirdList(object column, object delimiter) - { - expContext.Result = $"list({expContext.ParsedContent["column"]},{expContext.ParsedContent["delimiter"]})"; - return null; - } - public static string StringJoinGBaseWmConcatText(object column, object delimiter) - { - if (expContext.ParsedContent["delimiter"] == "','") - expContext.Result = $"wm_concat_text({expContext.ParsedContent["column"]})"; - else - throw new NotImplementedException(CoreStrings.GBase_NotSupport_OtherThanCommas); - //expContext.Result = $"replace(wm_concat_text({expContext.ParsedContent["column"]}), ',', {expContext.ParsedContent["delimiter"]})"; - return null; - } - #endregion - } + #region group_concat + public static IGroupConcat GroupConcat(object column) + { + if (expSb.Value == null) expSb.Value = new List(); + expSb.Value.Add(new ExpSbInfo()); + expSbLast.Sb.Append("group_concat(").Append(expContext.ParsedContent["column"]); + return null; + } + public static IGroupConcat Distinct(this IGroupConcat that) + { + if (expSbLast.IsDistinct == false) + { + expSbLast.Sb.Insert(expSbLast.Sb.ToString().LastIndexOf("group_concat(") + 13, "distinct "); + expSbLast.IsDistinct = true; + } + return that; + } + public static IGroupConcat Separator(this IGroupConcat that, object separator) + { + if (expSbLast.IsOrderBy) expSbLast.Sb.Remove(expSbLast.Sb.Length - 1, 1); + expSbLast.Sb.Append(" separator ").Append(expContext.ParsedContent["separator"]); + return that; + } + public static IGroupConcat OrderBy(this IGroupConcat that, object column) => OrderByPriv(that, false); + public static IGroupConcat OrderByDescending(this IGroupConcat that, object column) => OrderByPriv(that, true); + static IGroupConcat OrderByPriv(this IGroupConcat that, bool isDesc) + { + var sb = expSbLast.Sb; + if (expSbLast.IsOrderBy == false) + { + sb.Append(" order by "); + expSbLast.IsOrderBy = true; + } + var exp = expContext.RawExpression["column"]; + if (exp.NodeType == ExpressionType.New) + { + var expNew = exp as NewExpression; + for (var a = 0; a < expNew.Arguments.Count; a++) + { + sb.Append(expContext.Utility.ParseExpression(expNew.Arguments[a])); + if (isDesc) sb.Append(" desc"); + sb.Append(","); + } + } + else + { + sb.Append(expContext.ParsedContent["column"]); + if (isDesc) sb.Append(" desc"); + sb.Append(","); + } + return that; + } + public static string ToValue(this IGroupConcat that) + { + var sql = expSbLast.Sb.ToString().TrimEnd(','); + expSbLast.Sb.Clear(); + expSb.Value.RemoveAt(expSb.Value.Count - 1); + expContext.Result = $"{sql})"; + return default; + } + public interface IGroupConcat { } + #endregion + + #region string.Join 反射处理,此块代码用于反射,所以别修改定义 + public static string StringJoinSqliteGroupConcat(object column, object delimiter) + { + expContext.Result = $"group_concat({expContext.ParsedContent["column"]},{expContext.ParsedContent["delimiter"]})"; + return null; + } + public static string StringJoinPgsqlGroupConcat(object column, object delimiter) + { + expContext.Result = $"string_agg(({expContext.ParsedContent["column"]})::text,{expContext.ParsedContent["delimiter"]})"; + return null; + } + public static string StringJoinMySqlGroupConcat(object column, object delimiter) + { + expContext.Result = $"group_concat({expContext.ParsedContent["column"]} separator {expContext.ParsedContent["delimiter"]})"; + return null; + } + public static string StringJoinOracleGroupConcat(object column, object delimiter) + { + string orderby = null; + var subSelect = expContext._tsc?.subSelect001; + if (subSelect != null) + { + orderby = subSelect?._orderby?.Trim('\r', '\n'); + if (string.IsNullOrEmpty(orderby)) + { + var subSelectTb1 = subSelect._tables.FirstOrDefault(); + if (subSelectTb1 != null && subSelectTb1.Table.Primarys.Any() == true) + orderby = $"order by {string.Join(",", subSelectTb1.Table.Primarys.Select(a => $"{subSelectTb1.Alias}.{subSelect._commonUtils.QuoteSqlName(a.Attribute.Name)}"))}"; + } + } + if (string.IsNullOrEmpty(orderby)) orderby = "order by 1"; + expContext.Result = $"listagg(to_char({expContext.ParsedContent["column"]}),{expContext.ParsedContent["delimiter"]}) within group({orderby})"; + return null; + } + public static string StringJoinFirebirdList(object column, object delimiter) + { + expContext.Result = $"list({expContext.ParsedContent["column"]},{expContext.ParsedContent["delimiter"]})"; + return null; + } + public static string StringJoinGBaseWmConcatText(object column, object delimiter) + { + if (expContext.ParsedContent["delimiter"] == "','") + expContext.Result = $"wm_concat_text({expContext.ParsedContent["column"]})"; + else + throw new NotImplementedException(CoreStrings.GBase_NotSupport_OtherThanCommas); + //expContext.Result = $"replace(wm_concat_text({expContext.ParsedContent["column"]}), ',', {expContext.ParsedContent["delimiter"]})"; + return null; + } + #endregion + } } \ No newline at end of file