44using System . Linq ;
55using System . Text ;
66using System . Threading ;
7+ using static FreeSql . SqlExtExtensions ;
78
89[ ExpressionCall ]
910public static class FreeSqlGlobalExpressionCallExtensions
@@ -46,99 +47,215 @@ public static bool BetweenEnd(this DateTime that, DateTime start, DateTime end)
4647
4748namespace FreeSql
4849{
50+ /// <summary>
51+ /// SqlExt 是利用自定表达式函数解析功能,解析默认常用的SQL函数,欢迎 PR
52+ /// </summary>
4953 [ ExpressionCall ]
5054 public static class SqlExt
5155 {
52- public static ThreadLocal < ExpressionCallContext > expContext = new ThreadLocal < ExpressionCallContext > ( ) ;
56+ internal static ThreadLocal < ExpressionCallContext > expContext = new ThreadLocal < ExpressionCallContext > ( ) ;
5357
54- public static ISqlOver < long > Rank ( ) => Over < long > ( "RANK()" ) ;
55- public static ISqlOver < long > DenseRank ( ) => Over < long > ( "DENSE_RANK()" ) ;
56- public static ISqlOver < long > Count ( ) => Over < long > ( "COUNT()" ) ;
57- public static ISqlOver < decimal > Sum ( object column ) => Over < decimal > ( $ "Sum({ expContext . Value . ParsedContent [ "column" ] } )") ;
58- public static ISqlOver < decimal > Avg ( ) => Over < decimal > ( $ "AVG({ expContext . Value . ParsedContent [ "column" ] } )") ;
59- public static ISqlOver < T > Max < T > ( T column ) => Over < T > ( $ "MAX({ expContext . Value . ParsedContent [ "column" ] } )") ;
60- public static ISqlOver < T > Min < T > ( T column ) => Over < T > ( $ "MIN({ expContext . Value . ParsedContent [ "column" ] } )") ;
61- public static ISqlOver < long > RowNumber ( ) => Over < long > ( "ROW_NUMBER()" ) ;
58+ #region SqlServer/PostgreSQL over
59+ /// <summary>
60+ /// rank() over(order by ...)
61+ /// </summary>
62+ /// <returns></returns>
63+ public static ISqlOver < long > Rank ( ) => Over < long > ( "rank()" ) ;
64+ /// <summary>
65+ /// dense_rank() over(order by ...)
66+ /// </summary>
67+ /// <returns></returns>
68+ public static ISqlOver < long > DenseRank ( ) => Over < long > ( "dense_rank()" ) ;
69+ /// <summary>
70+ /// count() over(order by ...)
71+ /// </summary>
72+ /// <returns></returns>
73+ public static ISqlOver < long > Count ( ) => Over < long > ( "count()" ) ;
74+ /// <summary>
75+ /// sum(..) over(order by ...)
76+ /// </summary>
77+ /// <param name="column"></param>
78+ /// <returns></returns>
79+ public static ISqlOver < decimal > Sum ( object column ) => Over < decimal > ( $ "sum({ expContext . Value . ParsedContent [ "column" ] } )") ;
80+ /// <summary>
81+ /// avg(..) over(order by ...)
82+ /// </summary>
83+ /// <returns></returns>
84+ public static ISqlOver < decimal > Avg ( ) => Over < decimal > ( $ "avg({ expContext . Value . ParsedContent [ "column" ] } )") ;
85+ /// <summary>
86+ /// max(..) over(order by ...)
87+ /// </summary>
88+ /// <typeparam name="T"></typeparam>
89+ /// <param name="column"></param>
90+ /// <returns></returns>
91+ public static ISqlOver < T > Max < T > ( T column ) => Over < T > ( $ "max({ expContext . Value . ParsedContent [ "column" ] } )") ;
92+ /// <summary>
93+ /// min(..) over(order by ...)
94+ /// </summary>
95+ /// <typeparam name="T"></typeparam>
96+ /// <param name="column"></param>
97+ /// <returns></returns>
98+ public static ISqlOver < T > Min < T > ( T column ) => Over < T > ( $ "min({ expContext . Value . ParsedContent [ "column" ] } )") ;
99+ /// <summary>
100+ /// SqlServer row_number() over(order by ...)
101+ /// </summary>
102+ /// <returns></returns>
103+ public static ISqlOver < long > RowNumber ( ) => Over < long > ( "row_number()" ) ;
104+ #endregion
105+
106+ /// <summary>
107+ /// case when .. then .. end
108+ /// </summary>
109+ /// <returns></returns>
110+ public static ICaseWhenEnd Case ( ) => SqlExtExtensions . Case ( ) ;
111+ /// <summary>
112+ /// MySql group_concat(distinct .. order by .. separator ..)
113+ /// </summary>
114+ /// <param name="column"></param>
115+ /// <returns></returns>
116+ public static IGroupConcat GroupConcat ( object column ) => SqlExtExtensions . GroupConcat ( column ) ;
117+ }
118+
119+ [ ExpressionCall ]
120+ public static class SqlExtExtensions //这个类存在的意义,是不想使用者方法名污染
121+ {
122+ static ThreadLocal < ExpressionCallContext > expContextSelf = new ThreadLocal < ExpressionCallContext > ( ) ;
123+ static ExpressionCallContext expContext => expContextSelf . Value ?? SqlExt . expContext . Value ;
124+ internal static ThreadLocal < List < ExpSbInfo > > expSb = new ThreadLocal < List < ExpSbInfo > > ( ) ;
125+ internal static ExpSbInfo expSbLast => expSb . Value . Last ( ) ;
126+ internal class ExpSbInfo
127+ {
128+ public StringBuilder Sb { get ; } = new StringBuilder ( ) ;
129+ public bool IsOrderBy = false ;
130+ public bool IsDistinct = false ;
131+ }
62132
63133 #region .. over([partition by ..] order by ...)
64- static ThreadLocal < StringBuilder > expOverSb = new ThreadLocal < StringBuilder > ( ) ;
65- static ThreadLocal < bool > expOverSbIsOrderBy = new ThreadLocal < bool > ( ) ;
66- static ISqlOver < TValue > Over < TValue > ( string sqlFunc )
134+ internal static ISqlOver < TValue > Over < TValue > ( string sqlFunc )
67135 {
68- expOverSb . Value = new StringBuilder ( ) ;
69- expOverSbIsOrderBy . Value = false ;
70- expOverSb . Value . Append ( $ " { sqlFunc } ") ;
136+ if ( expSb . Value == null ) expSb . Value = new List < ExpSbInfo > ( ) ;
137+ expSb . Value . Add ( new ExpSbInfo ( ) ) ;
138+ expSbLast . Sb . Append ( sqlFunc ) . Append ( " ") ;
71139 return null ;
72140 }
73141 public static ISqlOver < TValue > Over < TValue > ( this ISqlOver < TValue > that )
74142 {
75- expOverSb . Value . Append ( "OVER (" ) ;
143+ expSbLast . Sb . Append ( "over (" ) ;
76144 return that ;
77145 }
78146 public static ISqlOver < TValue > PartitionBy < TValue > ( this ISqlOver < TValue > that , object column )
79147 {
80- expOverSb . Value . Append ( "PARTITION BY " ) . Append ( expContext . Value . ParsedContent [ "column" ] ) . Append ( "," ) ;
148+ expSbLast . Sb . Append ( " partition by " ) . Append ( expContext . ParsedContent [ "column" ] ) . Append ( "," ) ;
81149 return that ;
82150 }
83- public static ISqlOver < TValue > OrderBy < TValue > ( this ISqlOver < TValue > that , object column ) => OrderBy ( that , false ) ;
84- public static ISqlOver < TValue > OrderByDescending < TValue > ( this ISqlOver < TValue > that , object column ) => OrderBy ( that , true ) ;
85- static ISqlOver < TValue > OrderBy < TValue > ( this ISqlOver < TValue > that , bool isDesc )
151+ public static ISqlOver < TValue > OrderBy < TValue > ( this ISqlOver < TValue > that , object column ) => OrderByPriv ( that , false ) ;
152+ public static ISqlOver < TValue > OrderByDescending < TValue > ( this ISqlOver < TValue > that , object column ) => OrderByPriv ( that , true ) ;
153+ static ISqlOver < TValue > OrderByPriv < TValue > ( this ISqlOver < TValue > that , bool isDesc )
86154 {
87- var sb = expOverSb . Value ;
88- if ( expOverSbIsOrderBy . Value == false )
155+ var sb = expSbLast . Sb ;
156+ if ( expSbLast . IsOrderBy == false )
89157 {
90- sb . Append ( "ORDER BY " ) ;
91- expOverSbIsOrderBy . Value = true ;
158+ sb . Append ( " order by " ) ;
159+ expSbLast . IsOrderBy = true ;
92160 }
93- sb . Append ( expContext . Value . ParsedContent [ "column" ] ) ;
161+ sb . Append ( expContext . ParsedContent [ "column" ] ) ;
94162 if ( isDesc ) sb . Append ( " desc" ) ;
95163 sb . Append ( "," ) ;
96164 return that ;
97165 }
98166 public static TValue ToValue < TValue > ( this ISqlOver < TValue > that )
99167 {
100- var sb = expOverSb . Value . ToString ( ) . TrimEnd ( ',' ) ;
101- expOverSb . Value . Clear ( ) ;
102- expContext . Value . Result = $ "{ sb } )";
168+ var sql = expSbLast . Sb . ToString ( ) . TrimEnd ( ',' ) ;
169+ expSbLast . Sb . Clear ( ) ;
170+ expSb . Value . RemoveAt ( expSb . Value . Count - 1 ) ;
171+ expContext . Result = $ "{ sql } )";
103172 return default ;
104173 }
105174 public interface ISqlOver < TValue > { }
106175 #endregion
107176
108177 #region case when .. then .. when .. then .. end
109- static ThreadLocal < List < StringBuilder > > expCaseWhenEndSb = new ThreadLocal < List < StringBuilder > > ( ) ;
110178 public static ICaseWhenEnd Case ( )
111179 {
112- if ( expCaseWhenEndSb . Value == null ) expCaseWhenEndSb . Value = new List < StringBuilder > ( ) ;
113- expCaseWhenEndSb . Value . Add ( new StringBuilder ( ) . Append ( "CASE " ) ) ;
180+ if ( expSb . Value == null ) expSb . Value = new List < ExpSbInfo > ( ) ;
181+ expSb . Value . Add ( new ExpSbInfo ( ) ) ;
182+ expSbLast . Sb . Append ( "case " ) ;
114183 return null ;
115184 }
116185 public static ICaseWhenEnd < TValue > When < TValue > ( this ICaseWhenEnd that , bool test , TValue then )
117186 {
118- expCaseWhenEndSb . Value . Last ( ) . Append ( "\r \n WHEN " ) . Append ( expContext . Value . ParsedContent [ "test" ] ) . Append ( " THEN " ) . Append ( expContext . Value . ParsedContent [ "then" ] ) ;
187+ expSbLast . Sb . Append ( $ "\r \n { "" . PadRight ( expSb . Value . Count * 2 ) } when ") . Append ( expContext . ParsedContent [ "test" ] ) . Append ( " then " ) . Append ( expContext . ParsedContent [ "then" ] ) ;
119188 return null ;
120189 }
121190 public static ICaseWhenEnd < TValue > When < TValue > ( this ICaseWhenEnd < TValue > that , bool test , TValue then )
122191 {
123- expCaseWhenEndSb . Value . Last ( ) . Append ( "\r \n WHEN " ) . Append ( expContext . Value . ParsedContent [ "test" ] ) . Append ( " THEN " ) . Append ( expContext . Value . ParsedContent [ "then" ] ) ;
192+ expSbLast . Sb . Append ( $ "\r \n { "" . PadRight ( expSb . Value . Count * 2 ) } when ") . Append ( expContext . ParsedContent [ "test" ] ) . Append ( " then " ) . Append ( expContext . ParsedContent [ "then" ] ) ;
124193 return null ;
125194 }
126195 public static ICaseWhenEnd < TValue > Else < TValue > ( this ICaseWhenEnd < TValue > that , TValue then )
127196 {
128- expCaseWhenEndSb . Value . Last ( ) . Append ( "\r \n ELSE " ) . Append ( expContext . Value . ParsedContent [ "then" ] ) ;
197+ expSbLast . Sb . Append ( $ "\r \n { "" . PadRight ( expSb . Value . Count * 2 ) } else ") . Append ( expContext . ParsedContent [ "then" ] ) ;
129198 return null ;
130199 }
131200 public static TValue End < TValue > ( this ICaseWhenEnd < TValue > that )
132201 {
133- var sb = expCaseWhenEndSb . Value ;
134- var sql = sb . Last ( ) . Append ( "\r \n END" ) . ToString ( ) ;
135- sb . Last ( ) . Clear ( ) ;
136- sb . RemoveAt ( sb . Count - 1 ) ;
137- expContext . Value . Result = sql ;
202+ var sql = expSbLast . Sb . Append ( $ "\r \n { "" . PadRight ( expSb . Value . Count * 2 - 2 ) } end") . ToString ( ) ;
203+ expSbLast . Sb . Clear ( ) ;
204+ expSb . Value . RemoveAt ( expSb . Value . Count - 1 ) ;
205+ expContext . Result = sql ;
138206 return default ;
139207 }
140208 public interface ICaseWhenEnd { }
141209 public interface ICaseWhenEnd < TValue > { }
142210 #endregion
211+
212+ #region group_concat
213+ public static IGroupConcat GroupConcat ( object column )
214+ {
215+ if ( expSb . Value == null ) expSb . Value = new List < ExpSbInfo > ( ) ;
216+ expSb . Value . Add ( new ExpSbInfo ( ) ) ;
217+ expSbLast . Sb . Append ( "group_concat(" ) . Append ( expContext . ParsedContent [ "column" ] ) ;
218+ return null ;
219+ }
220+ public static IGroupConcat Distinct ( this IGroupConcat that )
221+ {
222+ if ( expSbLast . IsDistinct == false )
223+ {
224+ expSbLast . Sb . Insert ( expSbLast . Sb . ToString ( ) . LastIndexOf ( "group_concat(" ) + 13 , "distinct " ) ;
225+ expSbLast . IsDistinct = true ;
226+ }
227+ return that ;
228+ }
229+ public static IGroupConcat Separator ( this IGroupConcat that , object separator )
230+ {
231+ if ( expSbLast . IsOrderBy ) expSbLast . Sb . Remove ( expSbLast . Sb . Length - 1 , 1 ) ;
232+ expSbLast . Sb . Append ( " separator " ) . Append ( expContext . ParsedContent [ "separator" ] ) ;
233+ return that ;
234+ }
235+ public static IGroupConcat OrderBy ( this IGroupConcat that , object column ) => OrderByPriv ( that , false ) ;
236+ public static IGroupConcat OrderByDescending ( this IGroupConcat that , object column ) => OrderByPriv ( that , true ) ;
237+ static IGroupConcat OrderByPriv ( this IGroupConcat that , bool isDesc )
238+ {
239+ var sb = expSbLast . Sb ;
240+ if ( expSbLast . IsOrderBy == false )
241+ {
242+ sb . Append ( " order by " ) ;
243+ expSbLast . IsOrderBy = true ;
244+ }
245+ sb . Append ( expContext . ParsedContent [ "column" ] ) ;
246+ if ( isDesc ) sb . Append ( " desc" ) ;
247+ sb . Append ( "," ) ;
248+ return that ;
249+ }
250+ public static string ToValue ( this IGroupConcat that )
251+ {
252+ var sql = expSbLast . Sb . ToString ( ) . TrimEnd ( ',' ) ;
253+ expSbLast . Sb . Clear ( ) ;
254+ expSb . Value . RemoveAt ( expSb . Value . Count - 1 ) ;
255+ expContext . Result = $ "{ sql } )";
256+ return default ;
257+ }
258+ public interface IGroupConcat { }
259+ #endregion
143260 }
144261}
0 commit comments