Ejemplo n.º 1
0
 /// <summary>
 /// Checks if this expression binds any variables bound in the current group.
 /// </summary>
 private static bool ShouldSplit(ExpressionVariables vars, List <string> boundInGroup)
 {
     if (vars == null)
     {
         return(false);
     }
     if (vars.BindsNonTransparentParam)
     {
         return(true);
     }
     if (vars.Bound.Any(boundInGroup.Contains))
     {
         return(true);
     }
     return(false);
 }
Ejemplo n.º 2
0
 public LetStatement(string name, LambdaExpression expression, ExpressionVariables variables)
 {
     Name       = name;
     Expression = expression;
     Variables  = variables;
 }
Ejemplo n.º 3
0
 public BindProjectStatement(BindProjectPair expressions, ExpressionVariables bindVars, ExpressionVariables projectVars)
 {
     Expressions      = expressions;
     BindVariables    = bindVars;
     ProjectVariables = projectVars;
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Groups statements that can be fetched concurrently.
        /// </summary>
        public static List <ApplicativeGroup> MakeApplicative(LambdaExpression initial,
                                                              IEnumerable <QueryStatement> statements)
        {
            var applicatives = new List <ApplicativeGroup>();
            LambdaExpression    previousProject     = initial;
            ExpressionVariables previousProjectVars = null;
            var currentApplicative = new List <Statement>();
            var boundInGroup       = new List <string>();

            Action split = () =>
            {
                if (currentApplicative.Any())
                {
                    applicatives.Add(new ApplicativeGroup(currentApplicative));
                }
                currentApplicative = new List <Statement>();
                boundInGroup.Clear();
            };

            var first = true;

            foreach (var statement in statements)
            {
                var blockNumber = statement.BlockNumber;
                Func <LambdaExpression, string, BoundExpression>
                boundExpression = (e, s) => new BoundExpression(e, s, blockNumber);

                statement.Match(
                    bind =>
                {
                    // The result of the previous monad is bound to this variable name.
                    var previousBindName = bind.BindVariables.ParameterNames.First();
                    var prefixed         = PrefixedVariable(blockNumber, previousBindName);

                    if (first)     // Add the initial fetch.
                    {
                        currentApplicative.Add(new BindStatement(boundExpression(initial, prefixed)));
                    }

                    var shouldSplit = ShouldSplit(bind.BindVariables, boundInGroup);
                    if (shouldSplit)
                    {
                        split();
                    }

                    // If we're at the beginning of a new block, we should add the previous project statement.
                    if (bind.StartsBlock && !first)
                    {
                        var splitBlock = previousProjectVars != null && ShouldSplit(previousProjectVars, boundInGroup);
                        if (splitBlock)
                        {
                            split();
                        }
                        boundInGroup.Clear();
                        currentApplicative.Add(
                            // This project was from the previous block, so we subtract one here.
                            new ProjectStatement(new BoundExpression(previousProject, prefixed, blockNumber - 1)));
                        if (shouldSplit)
                        {
                            split();
                        }
                    }

                    // The result of the current monad is bound to the second parameter of the project fuction:
                    // x.SelectMany(
                    //     a => m a,
                    //     a, b => new { a, b }
                    //                   // ^ this b is the result of m a.
                    // )
                    var bindName         = bind.ProjectVariables.ParameterNames.Last();
                    var prefixedBindName = PrefixedVariable(blockNumber, bindName);
                    currentApplicative.Add(new BindStatement(boundExpression(bind.Expressions.Bind, prefixedBindName)));

                    // We take the final projection function and bind it to the HAXL_RESULT_NAME constant.
                    if (bind.IsFinal)
                    {
                        split();
                        currentApplicative.Add(new ProjectStatement(boundExpression(bind.Expressions.Project, HAXL_RESULT_NAME)));
                    }

                    // Push out the project function and its variables in case it's the final select of
                    // a nested block and we need to bind it.
                    previousProject     = bind.Expressions.Project;
                    previousProjectVars = bind.ProjectVariables;

                    // If we've split the only dependency is the current monad.
                    if (shouldSplit)
                    {
                        boundInGroup.Add(bindName);
                    }
                    else
                    {
                        boundInGroup.AddRange(bind.ProjectVariables.ParameterNames);
                    }
                    return(UnitVal);
                },
                    let =>
                {
                    var paramNames       = let.Variables.ParameterNames;
                    var previousBindName = paramNames.First();
                    var prefixed         = PrefixedVariable(blockNumber, previousBindName);
                    if (ShouldSplit(previousProjectVars, boundInGroup))
                    {
                        split();
                    }

                    // The initial lambda is always returns a monad, so we place it into a bind.
                    if (first)
                    {
                        currentApplicative.Add(new BindStatement(boundExpression(previousProject, prefixed)));
                    }
                    else if (!LetExpression.IsLetExpression(previousProject))
                    {
                        currentApplicative.Add(new ProjectStatement(boundExpression(previousProject, prefixed)));
                    }

                    boundInGroup.Add(let.Variables.ParameterNames.First());

                    if (ShouldSplit(let.Variables, boundInGroup))
                    {
                        split();
                    }

                    boundInGroup.Add(let.Name);
                    currentApplicative.Add(new ProjectStatement(boundExpression(let.Expression, PrefixedVariable(blockNumber, let.Name))));
                    return(UnitVal);
                }
                    );
                first = false;
            }
            if (currentApplicative.Any())
            {
                applicatives.Add(new ApplicativeGroup(currentApplicative));
            }
            return(applicatives);
        }