private QueryableMethodsVisitor PreEvaluateExpressionAndGetQueryableMethodsVisitor(ref Expression expression) { // replacing Count(predicate) with Where(predicate).Count() expression = ScalarMethodsVisitor.Visit(expression); // pre-executing everything, that can be executed locally expression = SubtreeEvaluator.Value.EvaluateSubtree(expression); // traversing the expression to find out the type of entities to be returned var entityTypeExtractor = new EntityTypeExtractionVisitor(); entityTypeExtractor.Visit(expression); if (entityTypeExtractor.TableEntityType == null) { throw new InvalidOperationException("Failed to extract the table entity type from the query"); } var entityType = entityTypeExtractor.EntityType ?? entityTypeExtractor.TableEntityType; // translating the query into set of conditions and converting the expression at the same time // (all Queryable method calls will be replaced by a param of IQueryable<T> type) var visitor = new QueryableMethodsVisitor(entityType, entityTypeExtractor.TableEntityType); expression = visitor.Visit(expression); visitor.TranslationResult.CustomizationHooks = this.CustomizationHooks; return(visitor); }
/// <summary> /// Evaluates LINQ expression and queries DynamoDb table for results /// </summary> internal object ExecuteQuery(Expression expression) { // replacing Count(predicate) with Where(predicate).Count() expression = ScalarMethodsVisitor.Visit(expression); // pre-executing everything, that can be executed locally expression = SubtreeEvaluator.Value.EvaluateSubtree(expression); // traversing the expression to find out the type of entities to be returned var entityTypeExtractor = new EntityTypeExtractionVisitor(); entityTypeExtractor.Visit(expression); if (entityTypeExtractor.TableEntityType == null) { throw new InvalidOperationException("Failed to extract the table entity type from the query"); } Type entityType = entityTypeExtractor.EntityType ?? entityTypeExtractor.TableEntityType; // translating the query into set of conditions and converting the expression at the same time // (all Queryable method calls will be replaced by a param of IQueryable<T> type) var visitor = new QueryableMethodsVisitor(entityType, entityTypeExtractor.TableEntityType); expression = visitor.Visit(expression); // executing get/query/scan operation against DynamoDb table var result = this._tableWrapper.LoadEntities(visitor.TranslationResult, entityType); // trying to support other (mostly Enumerable's single-entity) operations var enumerableResult = result as IEnumerable; if (enumerableResult != null) { var queryableResult = enumerableResult.AsQueryable(); var lambda = Expression.Lambda(expression, visitor.EnumerableParameterExp); // Here the default methods for IEnumerable<T> are called. // This allows to support First(), Last(), Any() etc. try { result = lambda.Compile().DynamicInvoke(queryableResult); } catch (TargetInvocationException ex) { throw ex.InnerException; } } return(result); }