/// <summary>
        /// Determines whether the supplied <see cref="BinaryExpression"/> is convertible to a binary in the context of the featureset of
        /// the Rebel 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));
        }
        private static void UpdateValuePredicateType(BindingSignatureSupport signatureSupport, BinaryExpression binaryExpression)
        {
            // Only modify the ValuePredicateType if it already is "Equals" or "Empty". This is pending a refactor
            // of BindingSignatureSupport to include a negation property and the removal of NotEquals

            if (signatureSupport.NodeType != ValuePredicateType.Equal && signatureSupport.NodeType != ValuePredicateType.Empty)
            {
                return;
            }

            // First check the NodeType. Binaries joined with "!= true" will have a NodeType of NotEqual
            switch (binaryExpression.NodeType)
            {
            case ExpressionType.Equal:
                signatureSupport.NodeType = ValuePredicateType.Equal;
                break;

            case ExpressionType.NotEqual:
                signatureSupport.NodeType = ValuePredicateType.NotEqual;
                break;

            case ExpressionType.GreaterThan:
                signatureSupport.NodeType = ValuePredicateType.GreaterThan;
                break;

            case ExpressionType.GreaterThanOrEqual:
                signatureSupport.NodeType = ValuePredicateType.GreaterThanOrEqual;
                break;

            case ExpressionType.LessThan:
                signatureSupport.NodeType = ValuePredicateType.LessThan;
                break;

            case ExpressionType.LessThanOrEqual:
                signatureSupport.NodeType = ValuePredicateType.LessThanOrEqual;
                break;
            }

            // Then check the Method, which might be an operator
            if (binaryExpression.Method != null)
            {
                switch (binaryExpression.Method.Name)
                {
                case "op_Inequality":
                    signatureSupport.NodeType = ValuePredicateType.NotEqual;
                    break;
                }
            }
        }
        public override FieldSelectorExpression CreateFieldSelector(MemberExpression expression, BindingSignatureSupport reportedSignatureSupport)
        {
            var attrib = GetAutoAttribute(expression);

            return(attrib == null?base.CreateFieldSelector(expression, reportedSignatureSupport) : new FieldSelectorExpression(attrib.Alias));
        }
Example #4
0
        /// <summary>
        /// Creates a <see cref="FieldSelectorExpression"/> from a <see cref="MethodCallExpression"/>.
        /// </summary>
        /// <param name="expression">The expression.</param>
        /// <param name="reportedSignatureSupport">A component outlining the supported expression structure of this provider.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public override FieldSelectorExpression CreateFieldSelector(MethodCallExpression expression, BindingSignatureSupport reportedSignatureSupport)
        {
            switch (expression.Method.Name)
            {
            case "Field":
                // This is an extension method for the RenderViewModel so the first argument is the extended object
                return(new FieldSelectorExpression(((ConstantExpression)expression.Arguments[1]).Value.ToString()));

            case "StringField":
                // This is an extension method for the RenderViewModel so the first argument is the extended object
                return(new FieldSelectorExpression(((ConstantExpression)expression.Arguments[1]).Value.ToString()));

            case "NumberField":
                // This is an extension method for the RenderViewModel so the first argument is the extended object
                return(new FieldSelectorExpression(((ConstantExpression)expression.Arguments[1]).Value.ToString()));

            case "BooleanField":
                // This is an extension method for the RenderViewModel so the first argument is the extended object
                return(new FieldSelectorExpression(((ConstantExpression)expression.Arguments[1]).Value.ToString()));

            case "get_Item":
                // This is the default accessor of a Dictionary, so check if the parent object is supported too
                if (ExpressionHelper.IsMember(expression.Object) && IsSupportedMember(expression.Object as MemberExpression).SignatureSupportType != SignatureSupportType.NotSupported)
                {
                    return(new FieldSelectorExpression(((ConstantExpression)expression.Arguments[0]).Value.ToString()));
                }
                break;
            }

            return(base.CreateFieldSelector(expression, reportedSignatureSupport));
        }
 /// <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);
 }
        /// <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 <see cref="FieldSelectorExpression"/> from a <see cref="MethodCallExpression"/>.
        /// </summary>
        /// <param name="expression">The expression.</param>
        /// <param name="reportedSignatureSupport">A component outlining the supported expression structure of this provider.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public override FieldSelectorExpression CreateFieldSelector(MethodCallExpression expression, BindingSignatureSupport reportedSignatureSupport)
        {
            switch (expression.Method.Name)
            {
            case "Attribute":
                // This is an extension method for the Persistence model so the first argument is the extended object

                if (expression.Arguments.Count == 3)
                {
                    //if there are 3 arguments, then we are selecting a field by name with a value key
                    return(new FieldSelectorExpression(
                               ((ConstantExpression)expression.Arguments[1]).Value.ToString(),
                               ((ConstantExpression)expression.Arguments[2]).Value.ToString()));
                }
                if (expression.Arguments.Count == 2)
                {
                    //if there are 2 arguments, then we are selecting a field only by name regardless of the value key
                    return(new FieldSelectorExpression(((ConstantExpression)expression.Arguments[1]).Value.ToString()));
                }
                break;

            case "get_Item":
                // This is the default accessor of a Dictionary, so check if the parent object is supported too
                if (ExpressionHelper.IsMember(expression.Object) && IsSupportedMember(expression.Object as MemberExpression).SignatureSupportType != SignatureSupportType.NotSupported)
                {
                    return(new FieldSelectorExpression(((ConstantExpression)expression.Arguments[0]).Value.ToString()));
                }

                // There are two dictionaries on this model, the TypedAttributeCollection and its child TypedAttributeValueCollection.
                // Make sure we're getting the field name from the TypedAttributeCollection indexer. To do this, access the MemberExpression
                // "one up the chain" and recurse back into this method.
                if (ExpressionHelper.IsMember(expression.Object) && ExpressionHelper.IsMethod(((MemberExpression)expression.Object).Expression))
                {
                    return(CreateFieldSelector(((MemberExpression)expression.Object).Expression as MethodCallExpression, reportedSignatureSupport));
                }

                break;
            }

            return(base.CreateFieldSelector(expression, reportedSignatureSupport));
        }
        /// <summary>
        /// Creates a field selector.
        /// </summary>
        /// <param name="fieldName">Name of the field.</param>
        /// <param name="innerFieldName">Name of the inner field.</param>
        /// <param name="reportedSignatureSupport">The reported signature support.</param>
        /// <returns></returns>
        public override FieldSelectorExpression CreateFieldSelector(string fieldName, string innerFieldName, BindingSignatureSupport reportedSignatureSupport)
        {
            switch (fieldName)
            {
            case "Name":
                return(new FieldSelectorExpression("system-internal-node-name", fieldName));

            case "UrlName":
                return(new FieldSelectorExpression("system-internal-node-name", fieldName));

            case "Template":
            case "TemplateId":
            case "CurrentTemplate":
                return(new FieldSelectorExpression("system-internal-selected-template", "TemplateId"));

            default:
                return(base.CreateFieldSelector(fieldName, innerFieldName, reportedSignatureSupport));
            }
        }