private void HandleReduceDefinition(ConstructorDeclaration ctor) { try { if (!indexDefinition.IsMapReduce) { return; } VariableInitializer reduceDefinition; AstNode groupBySource; string groupByParameter; string groupByIdentifier; if (indexDefinition.Reduce.Trim().StartsWith("from")) { reduceDefinition = QueryParsingUtils.GetVariableDeclarationForLinqQuery(indexDefinition.Reduce, RequiresSelectNewAnonymousType); var queryExpression = ((QueryExpression)reduceDefinition.Initializer); var queryContinuationClause = queryExpression.Clauses.OfType <QueryContinuationClause>().FirstOrDefault(); if (queryContinuationClause == null) { throw new IndexCompilationException("Reduce query must contain a 'group ... into ...' clause") { ProblematicText = indexDefinition.Reduce, IndexDefinitionProperty = "Reduce", }; } var queryGroupClause = queryContinuationClause.PrecedingQuery.Clauses.OfType <QueryGroupClause>().FirstOrDefault(); if (queryGroupClause == null) { throw new IndexCompilationException("Reduce query must contain a 'group ... into ...' clause") { ProblematicText = indexDefinition.Reduce, IndexDefinitionProperty = "Reduce", }; } groupByIdentifier = queryContinuationClause.Identifier; groupBySource = queryGroupClause.Key; groupByParameter = queryContinuationClause.PrecedingQuery.Clauses.OfType <QueryFromClause>().First().Identifier; } else { reduceDefinition = QueryParsingUtils.GetVariableDeclarationForLinqMethods(indexDefinition.Reduce, RequiresSelectNewAnonymousType); var initialInvocation = ((InvocationExpression)reduceDefinition.Initializer); var invocation = initialInvocation; var target = (MemberReferenceExpression)invocation.Target; while (target.MemberName != "GroupBy") { if (!(target.Target is InvocationExpression)) { // we've reached the initial results variable without encountering a GroupBy call throw new IndexCompilationException("Reduce expression must contain a call to GroupBy") { ProblematicText = indexDefinition.Reduce, IndexDefinitionProperty = "Reduce", }; } invocation = (InvocationExpression)target.Target; target = (MemberReferenceExpression)invocation.Target; } var lambdaExpression = GetLambdaExpression(invocation); groupByParameter = lambdaExpression.Parameters.First().Name; groupBySource = lambdaExpression.Body; groupByIdentifier = null; } var mapFields = captureSelectNewFieldNamesVisitor.FieldNames.ToList(); captureSelectNewFieldNamesVisitor.Clear(); // reduce override the map fields reduceDefinition.Initializer.AcceptVisitor(captureSelectNewFieldNamesVisitor, null); reduceDefinition.Initializer.AcceptVisitor(captureQueryParameterNamesVisitorForReduce, null); reduceDefinition.Initializer.AcceptVisitor(new ThrowOnInvalidMethodCalls(groupByIdentifier), null); ValidateMapReduceFields(mapFields); // this.ReduceDefinition = from result in results...; ctor.Body.Statements.Add(new ExpressionStatement( new AssignmentExpression( new MemberReferenceExpression(new ThisReferenceExpression(), "ReduceDefinition"), AssignmentOperatorType.Assign, new LambdaExpression { Parameters = { new ParameterDeclaration(null, "results") }, Body = reduceDefinition.Initializer.Clone() }))); ctor.Body.Statements.Add(new ExpressionStatement( new AssignmentExpression( new MemberReferenceExpression(new ThisReferenceExpression(), "GroupByExtraction"), AssignmentOperatorType.Assign, new LambdaExpression { Parameters = { new ParameterDeclaration(null, groupByParameter) }, Body = groupBySource.Clone() }))); } catch (InvalidOperationException ex) { throw new IndexCompilationException(ex.Message) { ProblematicText = indexDefinition.Reduce, IndexDefinitionProperty = "Reduce", }; } }
private void HandleReduceDefintion(ConstructorDeclaration ctor) { if (!indexDefinition.IsMapReduce) { return; } VariableDeclaration reduceDefiniton; Expression groupBySource; string groupByParamter; if (indexDefinition.Reduce.Trim().StartsWith("from")) { reduceDefiniton = QueryParsingUtils.GetVariableDeclarationForLinqQuery(indexDefinition.Reduce, RequiresSelectNewAnonymousType); var sourceSelect = (QueryExpression)((QueryExpression)reduceDefiniton.Initializer).FromClause.InExpression; groupBySource = ((QueryExpressionGroupClause)sourceSelect.SelectOrGroupClause).GroupBy; groupByParamter = sourceSelect.FromClause.Identifier; } else { reduceDefiniton = QueryParsingUtils.GetVariableDeclarationForLinqMethods(indexDefinition.Reduce, RequiresSelectNewAnonymousType); var invocation = ((InvocationExpression)reduceDefiniton.Initializer); var target = (MemberReferenceExpression)invocation.TargetObject; while (target.MemberName != "GroupBy") { invocation = (InvocationExpression)target.TargetObject; target = (MemberReferenceExpression)invocation.TargetObject; } var lambdaExpression = GetLambdaExpression(invocation); groupByParamter = lambdaExpression.Parameters[0].ParameterName; groupBySource = lambdaExpression.ExpressionBody; } var mapFields = captureSelectNewFieldNamesVisitor.FieldNames.ToList(); captureSelectNewFieldNamesVisitor.Clear(); // reduce override the map fields reduceDefiniton.Initializer.AcceptVisitor(captureSelectNewFieldNamesVisitor, null); reduceDefiniton.Initializer.AcceptChildren(captureQueryParameterNamesVisitorForReduce, null); reduceDefiniton.Initializer.AcceptVisitor(new ThrowOnInvalidMethodCalls(), null); ValidateMapReduceFields(mapFields); // this.ReduceDefinition = from result in results...; ctor.Body.AddChild(new ExpressionStatement( new AssignmentExpression( new MemberReferenceExpression(new ThisReferenceExpression(), "ReduceDefinition"), AssignmentOperatorType.Assign, new LambdaExpression { Parameters = { new ParameterDeclarationExpression(null, "results") }, ExpressionBody = reduceDefiniton.Initializer }))); ctor.Body.AddChild(new ExpressionStatement( new AssignmentExpression( new MemberReferenceExpression(new ThisReferenceExpression(), "GroupByExtraction"), AssignmentOperatorType.Assign, new LambdaExpression { Parameters = { new ParameterDeclarationExpression(null, groupByParamter) }, ExpressionBody = groupBySource }))); }