Exemple #1
0
        private ContainsExpression VisitContains(MethodCallExpression expression)
        {
            // Handle extension methods defined by Linqs
            if (IsDeclaring(expression, typeof(Queryable), typeof(Enumerable)))
            {
                AExpression values = Visit <AExpression>(expression.Arguments[0]);
                AExpression value  = Visit <AExpression>(expression.Arguments[1]);
                return(new ContainsExpression(values, value));
            }

            // Handle custom extension method
            if (IsDeclaring(expression, typeof(SqlQueryableHelper)))
            {
                // Get value expression first, because the source will change to the subquery making the value out of scope
                AExpression value = Visit <AExpression>(expression.Arguments[2]);

                // Evaluate the subquery expressions
                ASourceExpression source      = Visit <ASourceExpression>(expression.Arguments[0]);
                LambdaExpression  fieldLambda = (LambdaExpression)StripQuotes(expression.Arguments[1]);
                FieldExpression   field       = Visit <FieldExpression>(fieldLambda.Body);

                // Create the expression
                return(new ContainsExpression(new ScalarExpression(source, field), value));
            }

            throw new MethodTranslationException(expression.Method);
        }
Exemple #2
0
        public object Execute(Expression expression)
        {
            // Translate the expression tree
            expression = LinqTranslatorVisitor.Translate(expression);

            // Covert prediate (scalar) expressions to a source query
            if (expression is APredicateExpression predicate)
            {
                FieldExpression value = new FieldExpression(predicate, "Scalar", "Value");
                expression = new ScalarExpression(null, value);
            }

            // Covert aggregate (scalar) expressions to a source query
            if (expression is AggregateExpression aggregate)
            {
                FieldExpression value = new FieldExpression(aggregate, "Scalar", "Value");
                expression = new ScalarExpression(aggregate.Source, value);
            }

            // Execute the query
            if (expression is ASourceExpression source)
            {
                return(connection.ExecuteQuery(source, visitor));
            }

            throw new NotSupportedException("The expression could not be converted to sql.");
        }
Exemple #3
0
        /// <summary>
        /// Initializes a new instance of <see cref="Ordering"/> with the specified field and order direction.
        /// </summary>
        /// <param name="field">The field to order.</param>
        /// <param name="type">The direction to order the column.</param>
        public Ordering(FieldExpression field, OrderType type)
        {
            if (field == null)
            {
                throw new ArgumentNullException(nameof(field));
            }

            Field     = field;
            OrderType = type;
        }
        /// <summary>
        /// Initializes a new instance of <see cref="AggregateExpression"/> with the specified source and function.
        /// </summary>
        /// <param name="source">The source expression to perform the aggregate function on.</param>
        /// <param name="field">The field the aggregate function is applied to.</param>
        /// <param name="value">The type of aggregate operation to perform.</param>
        public AggregateExpression(ASourceExpression source, FieldExpression field, AggregateFunction function)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (field == null)
                throw new ArgumentNullException(nameof(field));

            Source = source;
            SourceField = field;
            Function = function;
        }
        public JoinExpression VisitJoin(MethodCallExpression expression)
        {
            // Handle the default Queryable extension Join
            if (IsDeclaring(expression, typeof(Queryable), typeof(Enumerable)))
            {
                // Resolve the sources
                ASourceExpression outer = Visit <ASourceExpression>(expression.Arguments[0]);
                ASourceExpression inner = Visit <ASourceExpression>(expression.Arguments[1]);

                // Set the active expressions (so fields calls can find their expression)
                sources = new[] { outer, inner };

                // Create the predicate
                LambdaExpression     outerLambda = (LambdaExpression)StripQuotes(expression.Arguments[2]);
                LambdaExpression     innerLambda = (LambdaExpression)StripQuotes(expression.Arguments[3]);
                FieldExpression      outerField  = Visit <FieldExpression>(outerLambda.Body);
                FieldExpression      innerField  = Visit <FieldExpression>(innerLambda.Body);
                APredicateExpression predicate   = new CompositeExpression(outerField, innerField, CompositeOperator.Equal);

                // Decode the result selector
                IEnumerable <FieldExpression> fields = DecodeJoinSelector(expression.Arguments[4], outer.Fields, inner.Fields);

                // Create the expression
                return(new JoinExpression(outer, inner, predicate, fields, JoinType.Inner));
            }

            // Handle the default SqlQueryableHelper extension Join
            if (IsDeclaring(expression, typeof(SqlQueryableHelper)))
            {
                // Resolve the sources
                ASourceExpression outer = Visit <ASourceExpression>(expression.Arguments[0]);
                ASourceExpression inner = Visit <ASourceExpression>(expression.Arguments[1]);

                // Set the active expressions (so fields calls can find their expression)
                sources = new[] { outer, inner };

                // Create the predicate
                LambdaExpression     predicateLambda = (LambdaExpression)StripQuotes(expression.Arguments[2]);
                APredicateExpression predicate       = Visit <APredicateExpression>(predicateLambda.Body);

                // Decode the result selector
                IEnumerable <FieldExpression> fields = DecodeJoinSelector(expression.Arguments[3], outer.Fields, inner.Fields);

                // Resolve the join type
                ConstantExpression joinType = (ConstantExpression)expression.Arguments[4];

                // Create the expression
                return(new JoinExpression(outer, inner, predicate, fields, (JoinType)joinType.Value));
            }

            throw new MethodTranslationException(expression.Method);
        }
Exemple #6
0
        /// <summary>
        /// Visits the specified expression.
        /// </summary>
        /// <param name="expression">The expression to visit.</param>
        public virtual Expression VisitField(FieldExpression expression)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }
            if (Context.Source == null)
            {
                throw new InvalidOperationException($"A field cannot be visited unless an {nameof(ASourceExpression)} has been visited.");
            }

            if (!(expression.ValueExpression is ASourceExpression sourceValueExpression))
            {
                throw new InvalidOperationException($"A field exposed from a source expression must itself have an {nameof(ASourceExpression)}. Did you mean to call VisitFieldDeclaration?");
            }
Exemple #7
0
        private SelectExpression VisitOrderBy(MethodCallExpression expression)
        {
            MethodInfo method = expression.Method;

            if (IsDeclaring(expression, typeof(Queryable), typeof(Enumerable), typeof(SqlQueryableHelper)))
            {
                // Resolve the source
                ASourceExpression source = Visit <ASourceExpression>(expression.Arguments[0]);

                // Resolve the optional selector
                FieldExpression field = source.Fields.First();
                if (expression.Arguments.Count > 1)
                {
                    LambdaExpression lambda = (LambdaExpression)StripQuotes(expression.Arguments[1]);
                    field = Visit <FieldExpression>(lambda.Body);
                }

                // Decode the direction
                OrderType direction = method.Name.EndsWith("Descending") ? OrderType.Descending : OrderType.Ascending;

                // Handle an existing select expression
                if (source is SelectExpression select)
                {
                    if (method.Name.StartsWith("ThenBy") && !select.Orderings.Any())
                    {
                        throw new InvalidOperationException($"{method.Name} can only be applied to an ordered sequence.");
                    }
                    if (method.Name.StartsWith("OrderBy") && select.Orderings.Any())
                    {
                        throw new InvalidOperationException($"{method.Name} can only be applied to an unordered sequence.");
                    }

                    // Clone and modify the select expression
                    IEnumerable <FieldExpression> fields    = select.Fields.Select(x => x.SourceExpression);
                    IEnumerable <Ordering>        orderings = select.Orderings.Concat(new[] { new Ordering(field.SourceExpression, direction) });
                    return(new SelectExpression(select.Source, fields, select.Take, select.Skip, orderings));
                }

                // Create the expression
                if (method.Name.StartsWith("ThenBy"))
                {
                    throw new InvalidOperationException($"{method.Name} can only be applied to an ordered sequence.");
                }
                return(new SelectExpression(source, orderings: new[] { new Ordering(field, direction) }));
            }

            throw new MethodTranslationException(expression.Method);
        }
        /// <summary>
        /// Initializes a new instance of <see cref="FieldExpression"/>, selecting the specified field from the specified source.
        /// </summary>
        /// <param name="valueExpression">The fields <see cref="AExpression"/> representing the value of the field.</param>
        /// <param name="table">The table or table alias the field is exposed from.</param>
        /// <param name="field">The name of the field on the source.</param>
        /// <param name="sourceExpression">The optional field expression this instance is mapping.</param>
        public FieldExpression(AExpression valueExpression, string table, string field, FieldExpression sourceExpression = null)
        {
            if (valueExpression == null)
            {
                throw new ArgumentNullException(nameof(valueExpression));
            }
            if (string.IsNullOrWhiteSpace(table))
            {
                throw new ArgumentException("Cannot be whitespace.", nameof(table));
            }
            if (string.IsNullOrWhiteSpace(field))
            {
                throw new ArgumentException("Cannot be whitespace.", nameof(field));
            }

            ValueExpression  = valueExpression;
            TableName        = table;
            FieldName        = field;
            SourceExpression = sourceExpression;
        }
Exemple #9
0
        private AggregateExpression VisitCount(MethodCallExpression expression)
        {
            if (IsDeclaring(expression, typeof(Queryable), typeof(Enumerable), typeof(SqlQueryableHelper)))
            {
                // Map the source
                ASourceExpression source = Visit <ASourceExpression>(expression.Arguments[0]);

                // Resolve the optional predicate
                if (expression.Arguments.Count > 1)
                {
                    LambdaExpression     lambda    = (LambdaExpression)StripQuotes(expression.Arguments[1]);
                    APredicateExpression predicate = Visit <APredicateExpression>(lambda.Body);
                    source = new WhereExpression(source, predicate);
                }

                // Resolve the field to be counted (must be done after the source has been manipulated)
                FieldExpression field = source.Fields.First();

                // Create the expression
                return(new AggregateExpression(source, field, AggregateFunction.Count));
            }

            throw new MethodTranslationException(expression.Method);
        }
        private FieldExpression VisitField(MethodCallExpression expression)
        {
            if (sources == null)
            {
                throw new InvalidOperationException($"A field can only be visited if an {nameof(ASourceExpression)} has previously been visited.");
            }

            // Resolve the field name
            ConstantExpression fieldNameExpression = expression.Arguments.FirstOrDefault() as ConstantExpression;

            if (!expression.Method.DeclaringType.IsAssignableFrom(typeof(Dictionary <string, object>)))
            {
                throw new InvalidOperationException("The declaring type for a field expression must be a Dictionary<string, object>.");
            }
            if (expression.Method.ReturnType != typeof(object))
            {
                throw new InvalidOperationException("The return type for a field expression must be type of object.");
            }
            if (expression.Arguments.Count != 1 || fieldNameExpression?.Type != typeof(string))
            {
                throw new InvalidOperationException("The field name indexer for the field expression must contain exactly one string parameter.");
            }

            // Resolve the table name
            MethodCallExpression source = expression.Object as MethodCallExpression;
            ConstantExpression   tableNameExpression = source?.Arguments.FirstOrDefault() as ConstantExpression;

            if (source == null)
            {
                throw new InvalidOperationException($"The table instance object could not be resolved for the field: {fieldNameExpression.Value.ToString()}");
            }
            if (source.Method.Name != "get_Item")
            {
                throw new NotSupportedException("Only an array indexer can be used to resolve a fields table name.");
            }
            if (!source.Method.ReturnType.IsAssignableFrom(typeof(RecordItem)))
            {
                throw new InvalidOperationException($"When mapping a field, the table name must map to a {nameof(RecordItem)}.");
            }
            if (source.Arguments.Count != 1 || tableNameExpression?.Type != typeof(string))
            {
                throw new InvalidOperationException("The table name indexer for the field expression must contain exactly one string parameter.");
            }

            // Resolve the indexer values
            string tableName = tableNameExpression.Value as string;
            string fieldName = fieldNameExpression.Value as string;

            if (string.IsNullOrWhiteSpace(tableName))
            {
                throw new InvalidOperationException("The table name cannot be empty.");
            }
            if (string.IsNullOrWhiteSpace(fieldName))
            {
                throw new InvalidOperationException("The field name cannot be empty.");
            }

            // Get the field from the current source
            FieldExpression found = sources?
                                    .SelectMany(x => x.Fields)
                                    .FirstOrDefault(x => x.TableName == tableName && x.FieldName == fieldName);

            if (found == null)
            {
                throw new KeyNotFoundException($"The field [{tableName}].[{fieldName}] could not be found on the current source expression.");
            }

            return(found);
        }
Exemple #11
0
 /// <summary>
 /// Initializes a new instance of <see cref="ScalarExpression"/> selecting the specified field from the source.
 /// </summary>
 /// <param name="source">The source expression to select from.</param>
 /// <param name="field">The field to select from the source.</param>
 public ScalarExpression(ASourceExpression source, FieldExpression field)
     : base(source, field != null ? new[] { field } : throw new ArgumentNullException(nameof(field)))
 {
 }