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; 29 using System.Collections.Generic; 30 using System.Diagnostics; 31 using System.Globalization; 32 using System.Linq.Expressions; 33 using System.Linq; 34 using System.Collections.ObjectModel; 35 36 using DbLinq.Data.Linq.Sugar; 37 using DbLinq.Data.Linq.Sugar.ExpressionMutator; 38 using DbLinq.Data.Linq.Sugar.Expressions; 39 40 namespace DbLinq.Data.Linq.Sugar.Expressions 41 { 42 /// <summary> 43 /// Holds new expression types (sql related), all well as their operands 44 /// </summary> 45 [DebuggerDisplay("SpecialExpression {SpecialNodeType}")] 46 #if !MONO_STRICT 47 public 48 #endif 49 class SpecialExpression : OperandsMutableExpression, IExecutableExpression 50 { 51 public SpecialExpressionType SpecialNodeType { get { return (SpecialExpressionType)NodeType; } } 52 GetSpecialExpressionTypeType(SpecialExpressionType specialExpressionType, IList<Expression> operands)53 protected static Type GetSpecialExpressionTypeType(SpecialExpressionType specialExpressionType, IList<Expression> operands) 54 { 55 Type defaultType; 56 if (operands.Count > 0) 57 defaultType = operands[0].Type; 58 else 59 defaultType = null; 60 switch (specialExpressionType) // SETuse 61 { 62 case SpecialExpressionType.IsNull: 63 case SpecialExpressionType.IsNotNull: 64 return typeof(bool); 65 case SpecialExpressionType.Concat: 66 return typeof(string); 67 case SpecialExpressionType.Count: 68 return typeof(int); 69 case SpecialExpressionType.Exists: 70 return typeof(bool); 71 case SpecialExpressionType.Like: 72 return typeof(bool); 73 case SpecialExpressionType.Min: 74 case SpecialExpressionType.Max: 75 case SpecialExpressionType.Sum: 76 return defaultType; // for such methods, the type is related to the operands type 77 case SpecialExpressionType.Average: 78 return typeof(double); 79 case SpecialExpressionType.StringLength: 80 return typeof(int); 81 case SpecialExpressionType.ToUpper: 82 case SpecialExpressionType.ToLower: 83 return typeof(string); 84 case SpecialExpressionType.In: 85 return typeof(bool); 86 case SpecialExpressionType.Substring: 87 return defaultType; 88 case SpecialExpressionType.Trim: 89 case SpecialExpressionType.LTrim: 90 case SpecialExpressionType.RTrim: 91 return typeof(string); 92 case SpecialExpressionType.StringInsert: 93 return typeof(string); 94 case SpecialExpressionType.Replace: 95 return typeof(string); 96 case SpecialExpressionType.Remove: 97 return typeof(string); 98 case SpecialExpressionType.IndexOf: 99 return typeof(int); 100 case SpecialExpressionType.Year: 101 case SpecialExpressionType.Month: 102 case SpecialExpressionType.Day: 103 case SpecialExpressionType.Hour: 104 case SpecialExpressionType.Second: 105 case SpecialExpressionType.Minute: 106 case SpecialExpressionType.Millisecond: 107 return typeof(int); 108 case SpecialExpressionType.Now: 109 case SpecialExpressionType.Date: 110 return typeof(DateTime); 111 case SpecialExpressionType.DateDiffInMilliseconds: 112 return typeof(long); 113 case SpecialExpressionType.Abs: 114 case SpecialExpressionType.Exp: 115 case SpecialExpressionType.Floor: 116 case SpecialExpressionType.Ln: 117 case SpecialExpressionType.Log: 118 case SpecialExpressionType.Pow: 119 case SpecialExpressionType.Round: 120 case SpecialExpressionType.Sign: 121 case SpecialExpressionType.Sqrt: 122 return defaultType; 123 124 default: 125 throw Error.BadArgument("S0058: Unknown SpecialExpressionType value {0}", specialExpressionType); 126 } 127 } 128 SpecialExpression(SpecialExpressionType expressionType, params Expression[] operands)129 public SpecialExpression(SpecialExpressionType expressionType, params Expression[] operands) 130 : base((ExpressionType)expressionType, GetSpecialExpressionTypeType(expressionType, operands), operands) 131 { 132 } 133 SpecialExpression(SpecialExpressionType expressionType, IList<Expression> operands)134 public SpecialExpression(SpecialExpressionType expressionType, IList<Expression> operands) 135 : base((ExpressionType)expressionType, GetSpecialExpressionTypeType(expressionType, operands), operands) 136 { 137 } 138 Mutate2(IList<Expression> newOperands)139 protected override Expression Mutate2(IList<Expression> newOperands) 140 { 141 return new SpecialExpression((SpecialExpressionType)NodeType, newOperands); 142 } 143 Execute()144 public object Execute() 145 { 146 switch (SpecialNodeType) // SETuse 147 { 148 case SpecialExpressionType.IsNull: 149 return operands[0].Evaluate() == null; 150 case SpecialExpressionType.IsNotNull: 151 return operands[0].Evaluate() != null; 152 case SpecialExpressionType.Concat: 153 { 154 var values = new List<string>(); 155 foreach (var operand in operands) 156 { 157 var value = operand.Evaluate(); 158 if (value != null) 159 values.Add(System.Convert.ToString(value, CultureInfo.InvariantCulture)); 160 else 161 values.Add(null); 162 } 163 return string.Concat(values.ToArray()); 164 } 165 case SpecialExpressionType.Count: 166 { 167 var value = operands[0].Evaluate(); 168 // TODO: string is IEnumerable. See what we do here 169 if (value is IEnumerable) 170 { 171 int count = 0; 172 foreach (var dontCare in (IEnumerable)value) 173 count++; 174 return count; 175 } 176 // TODO: by default, shall we answer 1 or throw an exception? 177 return 1; 178 } 179 case SpecialExpressionType.Exists: 180 { 181 var value = operands[0].Evaluate(); 182 // TODO: string is IEnumerable. See what we do here 183 if (value is IEnumerable) 184 { 185 return true; 186 } 187 // TODO: by default, shall we answer 1 or throw an exception? 188 return false; 189 } 190 case SpecialExpressionType.Min: 191 { 192 decimal? min = null; 193 foreach (var operand in operands) 194 { 195 var value = System.Convert.ToDecimal(operand.Evaluate()); 196 if (!min.HasValue || value < min.Value) 197 min = value; 198 } 199 return System.Convert.ChangeType(min.Value, operands[0].Type); 200 } 201 case SpecialExpressionType.Max: 202 { 203 decimal? max = null; 204 foreach (var operand in operands) 205 { 206 var value = System.Convert.ToDecimal(operand.Evaluate()); 207 if (!max.HasValue || value > max.Value) 208 max = value; 209 } 210 return System.Convert.ChangeType(max.Value, operands[0].Type); 211 } 212 case SpecialExpressionType.Sum: 213 { 214 decimal sum = operands.Select(op => System.Convert.ToDecimal(op.Evaluate())).Sum(); 215 return System.Convert.ChangeType(sum, operands.First().Type); 216 } 217 case SpecialExpressionType.Average: 218 { 219 decimal sum = 0; 220 foreach (var operand in operands) 221 sum += System.Convert.ToDecimal(operand.Evaluate()); 222 return sum / operands.Count; 223 } 224 case SpecialExpressionType.StringLength: 225 return operands[0].Evaluate().ToString().Length; 226 case SpecialExpressionType.ToUpper: 227 return operands[0].Evaluate().ToString().ToUpper(); 228 case SpecialExpressionType.ToLower: 229 return operands[0].Evaluate().ToString().ToLower(); 230 case SpecialExpressionType.Substring: 231 return EvaluateStandardCallInvoke("SubString", operands); 232 case SpecialExpressionType.In: 233 throw new NotImplementedException(); 234 case SpecialExpressionType.Replace: 235 return EvaluateStandardCallInvoke("Replace", operands); 236 case SpecialExpressionType.Remove: 237 return EvaluateStandardCallInvoke("Remove", operands); 238 case SpecialExpressionType.IndexOf: 239 return EvaluateStandardCallInvoke("IndexOf", operands); 240 case SpecialExpressionType.Year: 241 return ((DateTime)operands[0].Evaluate()).Year; 242 case SpecialExpressionType.Month: 243 return ((DateTime)operands[0].Evaluate()).Month; 244 case SpecialExpressionType.Day: 245 return ((DateTime)operands[0].Evaluate()).Day; 246 case SpecialExpressionType.Hour: 247 return ((DateTime)operands[0].Evaluate()).Hour; 248 case SpecialExpressionType.Minute: 249 return ((DateTime)operands[0].Evaluate()).Minute; 250 case SpecialExpressionType.Second: 251 return ((DateTime)operands[0].Evaluate()).Second; 252 case SpecialExpressionType.Millisecond: 253 return ((DateTime)operands[0].Evaluate()).Millisecond; 254 case SpecialExpressionType.Now: 255 return DateTime.Now; 256 case SpecialExpressionType.Date: 257 return ((DateTime)operands[0].Evaluate()); 258 case SpecialExpressionType.DateDiffInMilliseconds: 259 return ((DateTime)operands[0].Evaluate()) - ((DateTime)operands[1].Evaluate()); 260 case SpecialExpressionType.Abs: 261 case SpecialExpressionType.Exp: 262 case SpecialExpressionType.Floor: 263 case SpecialExpressionType.Ln: 264 case SpecialExpressionType.Log: 265 case SpecialExpressionType.Pow: 266 case SpecialExpressionType.Round: 267 case SpecialExpressionType.Sign: 268 case SpecialExpressionType.Sqrt: 269 return EvaluateMathCallInvoke(SpecialNodeType, operands); 270 default: 271 throw Error.BadArgument("S0116: Unknown SpecialExpressionType ({0})", SpecialNodeType); 272 } 273 } 274 EvaluateMathCallInvoke(SpecialExpressionType SpecialNodeType, ReadOnlyCollection<Expression> operands)275 private object EvaluateMathCallInvoke(SpecialExpressionType SpecialNodeType, ReadOnlyCollection<Expression> operands) 276 { 277 return typeof(Math).GetMethod(SpecialNodeType.ToString(), operands.Skip(1).Select(op => op.Type).ToArray()) 278 .Invoke(null, operands.Skip(1).Select(op => op.Evaluate()).ToArray()); 279 } EvaluateStatardMemberAccess(string propertyName, ReadOnlyCollection<Expression> operands)280 protected object EvaluateStatardMemberAccess(string propertyName, ReadOnlyCollection<Expression> operands) 281 { 282 return operands[0].Type.GetProperty(propertyName).GetValue(operands.First().Evaluate(), null); 283 } EvaluateStandardCallInvoke(string methodName, ReadOnlyCollection<Expression> operands)284 protected object EvaluateStandardCallInvoke(string methodName, ReadOnlyCollection<Expression> operands) 285 { 286 return operands[0].Type.GetMethod(methodName, 287 operands.Skip(1).Select(op => op.Type).ToArray()) 288 .Invoke(operands[0].Evaluate(), 289 operands.Skip(1).Select(op => op.Evaluate()).ToArray()); 290 } 291 } 292 }