예제 #1
0
        /// <summary>
        /// Builds a query plan.
        /// </summary>
        /// <param name="messages">
        /// The messages.
        /// </param>
        /// <param name="data">
        /// The data.
        /// </param>
        /// <param name="node">
        /// The script.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public static IQueryPlan Build(IMessageWriter messages, INodeDataProvider data, Node node)
        {
            var generator = new QueryPlanBuilder(messages, data);

            generator.Visit(node);

            return(data.GetQueryPlan(node));
        }
            protected internal override Node VisitSelectSource(SelectSource node)
            {
                node = (SelectSource)base.VisitSelectSource(node);

                var selectQuery = QueryPlanBuilder.Build(this.messages, this.data, node.Select);
                var aliases     = new HashSet <string>(
                    new[]
                {
                    node.Alias,
                });

                var factory = Expression.New(
                    typeof(SelectDataSource).GetTypeInfo().DeclaredConstructors.First(),
                    Expression.Constant(selectQuery),
                    Expression.Constant(aliases));

                this.data.SetFactoryExpression(node, factory);

                return(node);
            }
예제 #3
0
        /// <summary>
        /// Gets a function that creates the values for the selected records from a row.
        /// </summary>
        /// <param name="expressions">
        /// The <see cref="AliasedSqlExpression"/>s to get the values for.
        /// </param>
        /// <param name="fieldList">
        /// A collection that will be filled with all the fields that are used in the select statement.
        /// </param>
        /// <param name="wildCardAliasList">
        /// A collection that will be filled with all the wildcards that are used in the select statement.
        /// </param>
        /// <param name="allSourceAliases">
        /// Contains all source aliases in the query, so when a global wildcard is found, all fields are added.
        /// </param>
        /// <returns>
        /// A delegate.
        /// </returns>
        private Delegate GetValueFactory([NotNull] IEnumerable <AliasedSqlExpression> expressions, ICollection <IField> fieldList, ICollection <string> wildCardAliasList, IEnumerable <string> allSourceAliases)
        {
            var row            = Expression.Parameter(typeof(Row), "row");
            var context        = Expression.Parameter(typeof(IExecutionContext), "context");
            var fieldFactories = new List <LambdaExpression>();

            var lambdaVisitor = new GenericVisitor
            {
                (ExecutionContextExpression e) => context,
                (SourceFieldExpression e) =>
                {
                    fieldList?.Add(new Field(e.SourceName, e.FieldName));

                    return(e.CreateGetter(row));
                },
                (UnaryExpression e) => e.NodeType == ExpressionType.Convert ? (e.Operand as SourceFieldExpression)?.CreateGetter(row, e.Type) : null,
            };

            Func <string, Expression, Expression <Func <IExecutionContext, Row, KeyValuePair <string, object> > > > convertToLambda = (alias, expression) =>
            {
                var lambda = lambdaVisitor.Visit(expression.EvaluateAsValue());
                lambda = lambda.Type == typeof(object) ? lambda : Expression.Convert(lambda, typeof(object));
                return(Expression.Lambda <Func <IExecutionContext, Row, KeyValuePair <string, object> > >(Expression.New(QueryPlanBuilder.KeyValuePairConstructor, Expression.Constant(alias), lambda.CatchErrors()), context, row));
            };

            Expression <ValueFactory> result = null;

            var wildcardIndex  = 0;
            var hasGlobalAlias = false;

            foreach (var expression in expressions)
            {
                if (expression.Expression is WildcardSqlExpression wildcard)
                {
                    if (wildcard.Source != null)
                    {
                        wildCardAliasList.Add(wildcard.Source);
                    }
                    else
                    {
                        hasGlobalAlias = true;
                    }

                    var sourcePrefix = $"{wildcard.Source}.";
                    var index        = wildcardIndex++;
                    var lambda       = string.IsNullOrEmpty(wildcard.Source)
                                     ? (Expression <ValueFactory>)((c, r) => r.ColumnNames.Select(cn => new KeyValuePair <string, object>($"{index}!{cn}", r[cn])))
                                     : (c, r) => r.ColumnNames.Where(cn => cn.StartsWith(sourcePrefix)).Select(cn => new KeyValuePair <string, object>($"{index}!{cn}", r[cn]));

                    lambda = lambda.ReplaceParameter(lambda.Parameters[0], context).ReplaceParameter(lambda.Parameters[1], row);

                    if (fieldFactories.Count != 0)
                    {
                        var fields = QueryPlanBuilder.ToArrayInit <ValueFactory>(fieldFactories);

                        result = result == null ? fields : QueryPlanBuilder.ConcatenateLambdas(result, fields);

                        fieldFactories.Clear();
                    }

                    result = result == null ? lambda : QueryPlanBuilder.ConcatenateLambdas(result, lambda);
                }
                else
                {
                    fieldFactories.Add(convertToLambda(expression.Alias, this.data.ConvertToLinqExpression(expression.Expression)));
                }
            }

            if (fieldFactories.Count != 0)
            {
                var fields = QueryPlanBuilder.ToArrayInit <ValueFactory>(fieldFactories);

                result = result == null ? fields : QueryPlanBuilder.ConcatenateLambdas(result, fields);
            }

            if (hasGlobalAlias)
            {
                foreach (var alias in allSourceAliases)
                {
                    wildCardAliasList.Add(alias);
                }
            }

            var asyncResult = (result ?? ((c, r) => Enumerable.Empty <KeyValuePair <string, object> >())).RewriteTasksToAsyncExpression();

            return(asyncResult.ReturnType == typeof(IEnumerable <KeyValuePair <string, object> >)
                       ? ((Expression <ValueFactory>)asyncResult).Compile()
                       : (Delegate)((Expression <AsyncValueFactory>)asyncResult).Compile());
        }