1 #region MIT license
2 //
3 // MIT license
4 //
5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 // THE SOFTWARE.
24 //
25 #endregion
26 
27 using System;
28 using System.Collections.Generic;
29 using System.Linq;
30 using System.Linq.Expressions;
31 
32 using DbLinq.Data.Linq.Sugar;
33 using DbLinq.Data.Linq.Sugar.ExpressionMutator;
34 using DbLinq.Data.Linq.Sugar.Expressions;
35 
36 namespace DbLinq.Data.Linq.Sugar.Implementation
37 {
38     internal class SpecialExpressionTranslator : ISpecialExpressionTranslator
39     {
40         /// <summary>
41         /// Translate a hierarchy's SpecialExpressions to Expressions
42         /// </summary>
43         /// <param name="expression"></param>
44         /// <returns></returns>
Translate(Expression expression)45         public Expression Translate(Expression expression)
46         {
47             return expression.Recurse(Analyzer);
48         }
49 
Analyzer(Expression expression)50         protected virtual Expression Analyzer(Expression expression)
51         {
52             if (expression is SpecialExpression)
53                 return Translate((SpecialExpression)expression);
54             else if (expression is StartIndexOffsetExpression)
55                 return Translate(((StartIndexOffsetExpression)expression).InnerExpression);
56             return expression;
57         }
58 
59         /// <summary>
60         /// Translates a SpecialExpression to standard Expression equivalent
61         /// </summary>
62         /// <param name="specialExpression"></param>
63         /// <returns></returns>
Translate(SpecialExpression specialExpression)64         protected virtual Expression Translate(SpecialExpression specialExpression)
65         {
66             var operands = specialExpression.Operands.ToList();
67             switch (specialExpression.SpecialNodeType)  // SETuse
68             {
69                 case SpecialExpressionType.IsNull:
70                     return TranslateIsNull(operands);
71                 case SpecialExpressionType.IsNotNull:
72                     return TranslateIsNotNull(operands);
73                 case SpecialExpressionType.Concat:
74                     return TranslateConcat(operands);
75                 //case SpecialExpressionType.Count:
76                 //    break;
77                 //case SpecialExpressionType.Like:
78                 //    break;
79                 //case SpecialExpressionType.Min:
80                 //    break;
81                 //case SpecialExpressionType.Max:
82                 //    break;
83                 //case SpecialExpressionType.Sum:
84                 //    break;
85                 //case SpecialExpressionType.Average:
86                 //    break;
87                 case SpecialExpressionType.StringLength:
88                     return TranslateStringLength(operands);
89                 case SpecialExpressionType.ToUpper:
90                     return GetStandardCallInvoke("ToUpper", operands);
91                 case SpecialExpressionType.ToLower:
92                     return GetStandardCallInvoke("ToLower", operands);
93                 //case SpecialExpressionType.In:
94                 //    break;
95 
96                 case SpecialExpressionType.StringInsert:
97                     return GetStandardCallInvoke("Insert", operands);
98                 case SpecialExpressionType.Substring:
99                 case SpecialExpressionType.Trim:
100                 case SpecialExpressionType.LTrim:
101                 case SpecialExpressionType.RTrim:
102                 case SpecialExpressionType.Replace:
103                 case SpecialExpressionType.Remove:
104                 case SpecialExpressionType.IndexOf:
105                 case SpecialExpressionType.Year:
106                 case SpecialExpressionType.Month:
107                 case SpecialExpressionType.Day:
108                 case SpecialExpressionType.Hour:
109                 case SpecialExpressionType.Minute:
110                 case SpecialExpressionType.Millisecond:
111                 case SpecialExpressionType.Date:
112                     return GetStandardCallInvoke(specialExpression.SpecialNodeType.ToString(), operands);
113                 case SpecialExpressionType.Now:
114                     return GetDateTimeNowCall(operands);
115                 case SpecialExpressionType.DateDiffInMilliseconds:
116                     return GetCallDateDiffInMilliseconds(operands);
117                 default:
118                     throw Error.BadArgument("S0078: Implement translator for {0}", specialExpression.SpecialNodeType);
119 
120             }
121         }
122 
GetCallDateDiffInMilliseconds(List<Expression> operands)123         private Expression GetCallDateDiffInMilliseconds(List<Expression> operands)
124         {
125             return Expression.MakeMemberAccess(Expression.Subtract(operands.First(), operands.ElementAt(1)),
126                                                 typeof(TimeSpan).GetProperty("TotalMilliseconds"));
127         }
128 
GetDateTimeNowCall(List<Expression> operands)129         private Expression GetDateTimeNowCall(List<Expression> operands)
130         {
131             return Expression.Call(typeof(DateTime).GetProperty("Now").GetGetMethod());
132         }
133 
TranslateStringLength(List<Expression> operands)134         private Expression TranslateStringLength(List<Expression> operands)
135         {
136             return Expression.MakeMemberAccess(operands[0], typeof(string).GetProperty("Length"));
137         }
138 
GetStandardCallInvoke(string methodName, List<Expression> operands)139         protected virtual Expression GetStandardCallInvoke(string methodName, List<Expression> operands)
140         {
141             var parametersExpressions = operands.Skip(1);
142             return Expression.Call(operands[0],
143                                    operands[0].Type.GetMethod(methodName, parametersExpressions.Select(op => op.Type).ToArray()),
144                                    parametersExpressions);
145         }
146 
147         //protected virtual Expression TranslateRemove(List<Expression> operands)
148         //{
149         //    if (operands.Count > 2)
150         //    {
151         //        return Expression.Call(operands[0],
152         //                            typeof(string).GetMethod("Remove", new[] { typeof(int), typeof(int) }),
153         //                            operands[1], operands[2]);
154         //    }
155         //    return Expression.Call(operands[0],
156         //                            typeof(string).GetMethod("Remove", new[] { typeof(int) }),
157         //                            operands[1]);
158         //}
159 
160         //protected virtual Expression TranslateStringIndexOf(List<Expression> operands)
161         //{
162         //    if (operands.Count == 2 && operands[1].Type == typeof(string))
163         //    {
164         //         return Expression.Call(operands[0],
165         //                            typeof(string).GetMethod("IndexOf", new[] { typeof(string)}),
166         //                            operands[1]);
167         //    }
168         //    throw new NotSupportedException();
169         //}
170 
171         //protected virtual Expression TranslateReplace(List<Expression> operands)
172         //{
173         //    if (operands.ElementAt(1).Type == typeof(string))
174         //    {
175         //        return Expression.Call(operands[0],
176         //                           typeof(string).GetMethod("Replace", new[] { typeof(string), typeof(string) }),
177         //                           operands[1], operands[2]);
178         //    }
179         //    return Expression.Call(operands[0],
180         //                        typeof(string).GetMethod("Replace", new[] { typeof(char), typeof(char) }),
181         //                        operands[1], operands[2]);
182         //}
183         //protected virtual Expression TranslateInsertString(List<Expression> operands)
184         //{
185         //    return Expression.Call(operands.First(), typeof(string).GetMethod("Insert"), operands[1], operands[2]);
186         //}
187 
188         //protected virtual Expression TranslateTrim(List<Expression> operands)
189         //{
190         //    return Expression.Call(operands.First(), typeof(string).GetMethod("Trim", new Type[] { }));
191         //}
192         //protected virtual Expression TranslateSubString(List<Expression> operands)
193         //{
194         //    if (operands.Count > 2)
195         //    {
196         //        return Expression.Call(operands[0],
197         //                               typeof(string).GetMethod("Substring", new[] { operands[1].Type, operands[2].Type }),
198         //                               operands[1], operands[2]);
199         //    }
200 
201         //    return Expression.Call(operands[0],
202         //                           typeof(string).GetMethod("Substring", new[] { operands[1].Type }),
203         //                           operands[1]);
204         //}
205 
206         //protected virtual Expression TranslateToLower(List<Expression> operands)
207         //{
208         //    return Expression.Call(operands[0], typeof(string).GetMethod("ToLower", new Type[0]));
209         //}
210 
211         //protected virtual Expression TranslateToUpper(List<Expression> operands)
212         //{
213         //    return Expression.Call(operands[0], typeof(string).GetMethod("ToUpper", new Type[0]));
214         //}
215 
TranslateConcat(List<Expression> operands)216         protected virtual Expression TranslateConcat(List<Expression> operands)
217         {
218             return Expression.Add(operands[0], operands[1]);
219         }
220 
TranslateIsNotNull(List<Expression> operands)221         protected virtual Expression TranslateIsNotNull(List<Expression> operands)
222         {
223             return Expression.NotEqual(operands[0], Expression.Constant(null));
224         }
225 
TranslateIsNull(List<Expression> operands)226         protected virtual Expression TranslateIsNull(List<Expression> operands)
227         {
228             return Expression.Equal(operands[0], Expression.Constant(null));
229         }
230     }
231 }