/// <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; }