// public methods /// <summary> /// Returns a string that represents the Expression. /// </summary> /// <param name="node">The Expression to format.</param> /// <returns>A string that represents the Expression.</returns> public static string ToString(Expression node) { var formatter = new ExpressionFormatter(); formatter.Visit(node); return formatter.ToString(); }
/// <summary> /// Translates a LINQ query expression tree. /// </summary> /// <param name="expression">The LINQ query expression tree.</param> public void Translate(Expression expression) { // when we reach the original MongoQueryable<TDocument> we're done var constantExpression = expression as ConstantExpression; if (constantExpression != null) { if (constantExpression.Type == typeof(SequoiaQueryable <>).MakeGenericType(DocumentType)) { return; } } var methodCallExpression = expression as MethodCallExpression; if (methodCallExpression != null) { TranslateMethodCall(methodCallExpression); return; } var message = string.Format("Don't know how to translate expression: {0}.", ExpressionFormatter.ToString(expression)); throw new NotSupportedException(message); }
private void TranslateMethodCall(MethodCallExpression methodCallExpression) { if (methodCallExpression.Arguments.Count == 0) { var message = string.Format("Method call expression has no arguments: {0}.", ExpressionFormatter.ToString(methodCallExpression)); throw new ArgumentOutOfRangeException("methodCallExpression", message); } var source = methodCallExpression.Arguments[0]; Translate(source); _lastExpression = source; if (_distinct != null) { var message = "No further operators may follow Distinct in a LINQ query."; throw new NotSupportedException(message); } var methodName = methodCallExpression.Method.Name; switch (methodName) { case "Any": TranslateAny(methodCallExpression); break; case "Count": case "LongCount": TranslateCount(methodCallExpression); break; case "Distinct": TranslateDistinct(methodCallExpression); break; case "ElementAt": case "ElementAtOrDefault": TranslateElementAt(methodCallExpression); break; case "First": case "FirstOrDefault": case "Single": case "SingleOrDefault": TranslateFirstOrSingle(methodCallExpression); break; case "Last": case "LastOrDefault": TranslateLast(methodCallExpression); break; case "Max": case "Min": TranslateMaxMin(methodCallExpression); break; case "OfType": TranslateOfType(methodCallExpression); break; case "OrderBy": case "OrderByDescending": TranslateOrderBy(methodCallExpression); break; case "Select": TranslateSelect(methodCallExpression); break; case "Skip": TranslateSkip(methodCallExpression); break; case "Take": TranslateTake(methodCallExpression); break; case "ThenBy": case "ThenByDescending": TranslateThenBy(methodCallExpression); break; case "WithIndex": TranslateWithIndex(methodCallExpression); break; case "Where": TranslateWhere(methodCallExpression); break; default: var message = string.Format("The {0} query operator is not supported.", methodName); throw new NotSupportedException(message); } }
// private static methods private static Type GetDocumentType(Expression expression) { // look for the innermost nested constant of type MongoQueryable<T> and return typeof(T) var constantExpression = expression as ConstantExpression; if (constantExpression != null) { var constantType = constantExpression.Type; if (constantType.IsGenericType) { var genericTypeDefinition = constantType.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(SequoiaQueryable <>)) { return(constantType.GetGenericArguments()[0]); } } } var methodCallExpression = expression as MethodCallExpression; if (methodCallExpression != null && methodCallExpression.Arguments.Count != 0) { return(GetDocumentType(methodCallExpression.Arguments[0])); } var message = string.Format("Unable to find document type of expression: {0}.", ExpressionFormatter.ToString(expression)); throw new ArgumentOutOfRangeException("expression", message); }