/* * /// <summary> * /// Retrieves the data from the source. * /// </summary> * /// <param name="context"> * /// The context. * /// </param> * /// <param name="query"> * /// The query expression. Can be <c>null</c>. * /// </param> * /// <returns> * /// A task returning the data set. * /// </returns> * public async Task<DataSet> GetDataAsync(IExecutionContext context, IQuery query) * { * * var leftRows = await context.MaterializeAsync(await this.GetDataAsync(context, this.left, query, query.GetFilter(context), Enumerable.Empty<OrderByExpression>()).ConfigureAwait(false)).ConfigureAwait(false); * * if (leftRows.Count == 0) * { * return DataSet.Empty(); * } * * var sortOrders = new List<OrderByExpression>(); * var filter = await this.CreateJoinFilterAsync(context, leftRows, sortOrders); * var rightRows = await context.MaterializeAsync(await this.GetDataAsync(context, this.right, query, filter, sortOrders).ConfigureAwait(false)); * * if (rightRows.Count == 0) * { * return this.isInnerJoin ? DataSet.Empty() : DataSet.FromEnumerable(rightRows); * } * * var joinFilter = this.GetFilter(context); * * return null; * } */ /// <summary> /// Creates the join filter. /// </summary> /// <param name="context"> /// The execution context. /// </param> /// <param name="leftRows"> /// The left rows. /// </param> /// <param name="sortOrders"> /// Will be filled with the sort orders for this join. /// </param> /// <returns> /// A task containing the the filter expression. /// </returns> private Task <Expression> CreateJoinFilterAsync(IExecutionContext context, IAsyncReadOnlyCollection <Row> leftRows, ICollection <OrderByExpression> sortOrders) { var filter = (Expression)null; // await this.GetFilter(context, null).ToRangedExpressionAsync(leftRows, this.right.Aliases); return(Task.FromResult(new GenericVisitor { (GenericVisitor visitor, BinaryExpression node) => { if (node.NodeType != ExpressionType.And && node.NodeType != ExpressionType.AndAlso) { return null; } Expression leftSide, rightSide; if (((leftSide = visitor.Visit(node.Left)) as ConstantExpression)?.Value?.Equals(true) ?? false) { return visitor.Visit(node.Right); } if (((rightSide = visitor.Visit(node.Right)) as ConstantExpression)?.Value?.Equals(true) ?? false) { return visitor.Visit(node.Left); } return Expression.MakeBinary(ExpressionType.AndAlso, leftSide, rightSide); }, (RangeExpression node) => node.Type == typeof(bool) && object.Equals(node.Min, false) && object.Equals(node.Max, true) ? (Expression)Expression.Constant(true) : node, (CompareExpression node) => { var field = node.Left as SourceFieldExpression; var range = node.Right as RangeExpression; if (field == null || range == null) { return null; } switch (node.CompareType) { case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: sortOrders.Add( new OrderByExpression( CustomExpression.MakeSourceField(field.SourceName, field.FieldName), node.CompareType == ExpressionType.GreaterThan || node.CompareType == ExpressionType.GreaterThanOrEqual)); break; } return Expression.AndAlso( CustomExpression.MakeCompare(ExpressionType.GreaterThanOrEqual, field, Expression.Constant(range.Min, range.Type)), CustomExpression.MakeCompare(ExpressionType.LessThanOrEqual, field, Expression.Constant(range.Max, range.Type))); }, }.Visit(filter))); }
/// <summary> /// Moves field expressions in comparisons to the left. /// </summary> /// <typeparam name="T"> /// The type of the expression. /// </typeparam> /// <param name="expression"> /// The expression. /// </param> /// <param name="source"> /// The source for which the fields should be moved to the left. /// </param> /// <returns> /// The <see cref="Expression"/>. /// </returns> public static T MoveFieldsToTheLeft <T>(this T expression, DataSource source) where T : Expression { return((T) new GenericVisitor { (CompareExpression node) => { if (!node.Right.ContainsField(source)) { return null; } var opposite = ExpressionExtensions.InvertComparison(node.CompareType); return opposite != null?CustomExpression.MakeCompare(opposite.Value, node.Right, node.Left) : null; }, }.Visit(expression)); }
/// <summary> /// The ranges to join filter. /// </summary> /// <param name="filter"> /// The filter. /// </param> /// <returns> /// The <see cref="Expression"/>. /// </returns> private static Expression RangesToJoinFilter(Expression filter) { return(GenericVisitor.Visit( (CompareExpression node) => { var field = node.Left as SourceFieldExpression; var range = node.Right as RangeExpression; if (field == null || range == null) { return null; } switch (node.CompareType) { case ExpressionType.Equal: return Expression.AndAlso( CustomExpression.MakeCompare(ExpressionType.GreaterThanOrEqual, field, Expression.Constant(range.Min, range.Type)), CustomExpression.MakeCompare(ExpressionType.LessThanOrEqual, field, Expression.Constant(range.Max, range.Type))); case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: return CustomExpression.MakeCompare(node.CompareType, field, Expression.Constant(range.Min, range.Type)); case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: return CustomExpression.MakeCompare(node.CompareType, field, Expression.Constant(range.Max, range.Type)); case ExpressionType.NotEqual: return Expression.Constant(true); default: return null; } }, filter)); }
/// <summary> /// The ranges to join filter. /// </summary> /// <param name="filter"> /// The filter. /// </param> /// <returns> /// The <see cref="Expression"/>. /// </returns> private static Expression RangesToJoinFilter(Expression filter) { return(GenericVisitor.Visit( (CompareExpression node) => { var rightRange = node.Right as RangeExpression; if (rightRange == null) { var leftRange = node.Left as RangeExpression; if (leftRange == null) { return null; } switch (node.CompareType) { case ExpressionType.Equal: return Expression.AndAlso( CustomExpression.MakeCompare(ExpressionType.GreaterThanOrEqual, leftRange.MinExpression, node.Right), CustomExpression.MakeCompare(ExpressionType.LessThanOrEqual, leftRange.MaxExpression, node.Right)); case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: return CustomExpression.MakeCompare(node.CompareType, leftRange.MinExpression, node.Right); case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: return CustomExpression.MakeCompare(node.CompareType, leftRange.MaxExpression, node.Right); case ExpressionType.NotEqual: return Expression.Constant(true); default: return null; } } switch (node.CompareType) { case ExpressionType.Equal: return Expression.AndAlso( CustomExpression.MakeCompare(ExpressionType.GreaterThanOrEqual, node.Left, rightRange.MinExpression), CustomExpression.MakeCompare(ExpressionType.LessThanOrEqual, node.Left, rightRange.MaxExpression)); case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: return CustomExpression.MakeCompare(node.CompareType, node.Left, rightRange.MinExpression); case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: return CustomExpression.MakeCompare(node.CompareType, node.Left, rightRange.MaxExpression); case ExpressionType.NotEqual: return Expression.Constant(true); default: return null; } }, filter)); }
/// <summary> /// Generates an expression for the '<>' operator. /// </summary> /// <param name="first"> /// The first argument. /// </param> /// <param name="second"> /// The second argument. /// </param> /// <returns> /// The generated expression. /// </returns> private static Expression GenerateNotEqual(Expression first, Expression second) { return(CustomExpression.MakeCompare(ExpressionType.NotEqual, first, second)); }
/// <summary> /// Generates an expression for the '<' operator. /// </summary> /// <param name="first"> /// The first argument. /// </param> /// <param name="second"> /// The second argument. /// </param> /// <returns> /// The generated expression. /// </returns> private static Expression GenerateLessThan(Expression first, Expression second) { return(CustomExpression.MakeCompare(ExpressionType.LessThan, first, second)); }