/// <summary>
        /// Determines whether the supplied <see cref="BinaryExpression"/> is convertible to a binary in the context of the featureset of
        /// the Umbraco Framework-supported expression tree.
        /// </summary>
        /// <param name="expression">The expression.</param>
        /// <param name="structureBinder">The structure binder.</param>
        /// <returns><c>true</c> if [is convertible binary] [the specified expression]; otherwise, <c>false</c>.</returns>
        /// <remarks></remarks>
        public static bool IsConvertibleBinary(BinaryExpression expression, AbstractQueryStructureBinder structureBinder)
        {
            var left = expression.Left;
            var right = expression.Right;

            BindingSignatureSupport bindingSignatureSupport = GetBindingSupport(left, structureBinder);

            return bindingSignatureSupport != null && (ExpressionHelper.IsConstant(right) || right is UnaryExpression);
        }
        /// <summary>
        /// Gets a <see cref="BindingSignatureSupport"/> from an expression.
        /// </summary>
        /// <param name="left">The left.</param>
        /// <param name="structureBinder">The structure binder.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        private static BindingSignatureSupport GetBindingSupport(Expression left, AbstractQueryStructureBinder structureBinder)
        {
            Func<MethodCallExpression, BindingSignatureSupport>
                getMethodSupport = x => ExpressionHelper.IsMethod(x) ? structureBinder.IsSupportedMethod(x) : null;

            Func<MemberExpression, BindingSignatureSupport>
                getMemberSupport = x => ExpressionHelper.IsMember(x) ? structureBinder.IsSupportedMember(x) : null;

            var supportedNonDynamic = getMemberSupport.Invoke(left as MemberExpression) ?? getMethodSupport.Invoke(left as MethodCallExpression);

            if (supportedNonDynamic == null)
            {
                var unary = left as UnaryExpression;
                if (unary != null)
                {
                    var innerMethod = unary.Operand as MethodCallExpression;
                    if (innerMethod != null)
                        return getMethodSupport.Invoke(innerMethod);
                }
            }

            return supportedNonDynamic;
        }
 /// <summary>
 /// Gets a <see cref="FieldSelectorExpression"/> from an expression it the <paramref name="bindingSignatureSupport"/> identifies it as supported.
 /// </summary>
 /// <param name="left">The left.</param>
 /// <param name="structureBinder">The structure binder.</param>
 /// <param name="bindingSignatureSupport">The binding signature support.</param>
 /// <returns></returns>
 /// <remarks></remarks>
 public static FieldSelectorExpression GetFieldSelector(Expression left, AbstractQueryStructureBinder structureBinder, BindingSignatureSupport bindingSignatureSupport)
 {
     switch (bindingSignatureSupport.SignatureSupportType)
     {
         case SignatureSupportType.SupportedAsFieldName:
             if (ExpressionHelper.IsMember(left))
                 return structureBinder.CreateFieldSelector(left as MemberExpression, bindingSignatureSupport);
             else if (ExpressionHelper.IsMethod(left))
                 return structureBinder.CreateFieldSelector(left as MethodCallExpression, bindingSignatureSupport);
             break;
     }
     return null;
 }
 private static SchemaSelectorExpression GetSchemaSelector(Expression left, AbstractQueryStructureBinder structureBinder, BindingSignatureSupport bindingSignatureSupport)
 {
     switch (bindingSignatureSupport.SignatureSupportType)
     {
         case SignatureSupportType.SupportedAsSchemaAlias:
             if (ExpressionHelper.IsMember(left))
                 return structureBinder.CreateSchemaSelector(left as MemberExpression, bindingSignatureSupport);
             else if (ExpressionHelper.IsMethod(left))
                 return structureBinder.CreateSchemaSelector(left as MethodCallExpression, bindingSignatureSupport);
             break;
     }
     return null;
 }
 public static FieldSelectorExpression GetFieldSelector(Expression left, AbstractQueryStructureBinder structureBinder)
 {
     var signatureSupport = GetBindingSupport(left, structureBinder);
     return GetFieldSelector(left, structureBinder, signatureSupport);
 }
        /// <summary>
        /// Converts a <see cref="BinaryExpression"/> to a field predicate expression, if supported and convertible.
        /// </summary>
        /// <param name="expression">The expression.</param>
        /// <param name="structureBinder">The structure binder.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static Expression ConvertToFieldPredicate(BinaryExpression expression, AbstractQueryStructureBinder structureBinder)
        {
            if (IsConvertibleBinary(expression, structureBinder))
            {
                var left = expression.Left;

                // Check if the left had side is a Unary wrapping a DynamicMemberMetadata call just to get the type right
                var unaryLeft = left as UnaryExpression;
                if (unaryLeft != null)
                {
                    var methodLeft = unaryLeft.Operand as MethodCallExpression;
                    if (methodLeft != null && methodLeft.Method == DynamicMemberMetadata.GetMemberMethod)
                    {
                        left = methodLeft;
                    }
                }

                // First assume that the right hand side of the binary is a constant
                ConstantExpression right = expression.Right as ConstantExpression;

                // If it's not, it might be a unary (e.g. "convert value to object" if it's from DynamicMemberMetadata)
                if (right == null)
                {
                    var unary = expression.Right as UnaryExpression;
                    if (unary != null)
                    {
                        // If it was a unary, ignore the operator and just go for the operand (the value)
                        right = unary.Operand as ConstantExpression;
                    }
                }

                BindingSignatureSupport leftBindingSignatureSupport = GetBindingSupport(left, structureBinder);

                // Update the ValuePredicateType based on the expression which might reference an operator or a NodeType of NotEqual etc.
                UpdateValuePredicateType(leftBindingSignatureSupport, expression);

                switch (leftBindingSignatureSupport.SignatureSupportType)
                {
                    case SignatureSupportType.SupportedAsFieldName:
                        var selectorExpression = GetFieldSelector(left, structureBinder, leftBindingSignatureSupport);
                        return new FieldPredicateExpression(selectorExpression, new FieldValueExpression(leftBindingSignatureSupport.NodeType, right.Value));
                    case SignatureSupportType.SupportedAsFieldValue:
                        var methodCallExpression = ((MethodCallExpression)left);
                        if (ExpressionHelper.IsMethod(left))
                        {
                            var fieldValueExpression = structureBinder
                                .CreateFieldValueExpression(methodCallExpression, leftBindingSignatureSupport);

                            var objectOfMethod = methodCallExpression.Object;
                            var bindingSupportForMethodObject = GetBindingSupport(objectOfMethod, structureBinder);
                            var fieldSelector = GetFieldSelector(objectOfMethod, structureBinder, bindingSupportForMethodObject);

                            return new FieldPredicateExpression(fieldSelector, fieldValueExpression);
                        }
                        break;
                    case SignatureSupportType.SupportedAsSchemaAlias:
                        var schemaSelectorExpression = GetSchemaSelector(left, structureBinder, leftBindingSignatureSupport);
                        return
                            new SchemaPredicateExpression(
                                new SchemaSelectorExpression(schemaSelectorExpression.Name),
                                new SchemaValueExpression(leftBindingSignatureSupport.NodeType, right.Value));
                }
            }

            return expression;
        }
 /// <summary>
 /// Creates a new <see cref="QueryModelVisitor"/>, and returns the result of running <see cref="QueryModelVisitor.VisitAndGenerateQueryDescription"/> on the
 /// supplied <paramref name="queryModel"/>.
 /// </summary>
 /// <param name="queryModel">The query model.</param>
 /// <param name="structureBinder">The structure binder.</param>
 /// <param name="treeVisitor">The tree visitor.</param>
 /// <returns></returns>
 /// <remarks></remarks>
 public static QueryDescription FromQueryModel(Remotion.Linq.QueryModel queryModel, AbstractQueryStructureBinder structureBinder, AbstractExpressionTreeVisitor treeVisitor)
 {
     var elrmv = new QueryModelVisitor(structureBinder, treeVisitor);
     return elrmv.VisitAndGenerateQueryDescription(queryModel);
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="QueryModelVisitor"/> class.
 /// </summary>
 /// <param name="structureBinder">The structure binder.</param>
 /// <param name="treeVisitor">The tree visitor.</param>
 /// <remarks></remarks>
 public QueryModelVisitor(AbstractQueryStructureBinder structureBinder, AbstractExpressionTreeVisitor treeVisitor)
 {
     _structureBinder = structureBinder;
     _treeVisitor = treeVisitor;
 }
 /// <summary>
 /// Rewrites the expression tree to a field predicate tree given an <see cref="AbstractQueryStructureBinder"/> implementation.
 /// </summary>
 /// <param name="expressionToVisit">The expression to visit.</param>
 /// <param name="structureBinder">The structure binder.</param>
 /// <returns></returns>
 /// <remarks></remarks>
 public static Expression RewriteToFieldPredicateTree(Expression expressionToVisit, AbstractQueryStructureBinder structureBinder)
 {
     var visitor = new DefaultExpressionTreeVisitor(structureBinder);
     return visitor.VisitExpression(expressionToVisit);
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="DefaultExpressionTreeVisitor"/> class.
 /// </summary>
 /// <param name="structureBinder">The structure binder.</param>
 /// <remarks></remarks>
 public DefaultExpressionTreeVisitor(AbstractQueryStructureBinder structureBinder)
 {
     StructureBinder = structureBinder;
 }