/// <summary> /// Visits a nest against either a constant expression of IBucketQueryable, or a subquery based on an IBucketQueryable /// </summary> /// <param name="nestClause">Nest clause being visited</param> /// <returns>N1QlFromQueryPart to be added to the QueryPartsAggregator</returns> private N1QlFromQueryPart ParseNestClause(NestClause nestClause) { switch (nestClause.InnerSequence.NodeType) { case ExpressionType.Constant: return(VisitConstantExpressionNestClause(nestClause, nestClause.InnerSequence as ConstantExpression, GetExtentName(nestClause))); case SubQueryExpression.ExpressionType: // SubQueryExpression var subQuery = nestClause.InnerSequence as SubQueryExpression; if ((subQuery == null) || subQuery.QueryModel.ResultOperators.Any() || subQuery.QueryModel.MainFromClause.FromExpression.NodeType != ExpressionType.Constant) { throw new NotSupportedException("Unsupported Nest Inner Sequence"); } // Generate a temporary item name to use on the NEST statement, which we can then reference in the LET statement var genItemName = _queryGenerationContext.ExtentNameProvider.GetUnlinkedExtentName(); var fromPart = VisitConstantExpressionNestClause(nestClause, subQuery.QueryModel.MainFromClause.FromExpression as ConstantExpression, genItemName); // Put any where clauses in the sub query in an ARRAY filtering clause using a LET statement var whereClauseString = string.Join(" AND ", subQuery.QueryModel.BodyClauses.OfType <WhereClause>() .Select(p => GetN1QlExpression(p.Predicate))); var letPart = new N1QlLetQueryPart() { ItemName = GetExtentName(nestClause), Value = string.Format("ARRAY {0} FOR {0} IN {1} WHEN {2} END", GetExtentName(subQuery.QueryModel.MainFromClause), genItemName, whereClauseString) }; _queryPartsAggregator.AddLetPart(letPart); if (!nestClause.IsLeftOuterNest) { // This is an INNER NEST, but the inner sequence filter is being applied after the NEST operation is done // So we need to put an additional filter to drop rows with an empty array result _queryPartsAggregator.AddWherePart("(ARRAY_LENGTH({0}) > 0)", letPart.ItemName); } return(fromPart); default: throw new NotSupportedException("Unsupported Nest Inner Sequence"); } }
public void AddLetPart(N1QlLetQueryPart letPart) { LetParts.Add(letPart); }
/// <summary> /// Visits a nest against either a constant expression of IBucketQueryable, or a subquery based on an IBucketQueryable /// </summary> /// <param name="nestClause">Nest clause being visited</param> /// <returns>N1QlFromQueryPart to be added to the QueryPartsAggregator</returns> private N1QlFromQueryPart ParseNestClause(NestClause nestClause) { switch (nestClause.InnerSequence.NodeType) { case ExpressionType.Constant: return VisitConstantExpressionNestClause(nestClause, nestClause.InnerSequence as ConstantExpression, GetExtentName(nestClause)); case SubQueryExpression.ExpressionType: // SubQueryExpression var subQuery = nestClause.InnerSequence as SubQueryExpression; if ((subQuery == null) || subQuery.QueryModel.ResultOperators.Any() || subQuery.QueryModel.MainFromClause.FromExpression.NodeType != ExpressionType.Constant) { throw new NotSupportedException("Unsupported Nest Inner Sequence"); } // Generate a temporary item name to use on the NEST statement, which we can then reference in the LET statement var genItemName = _queryGenerationContext.ExtentNameProvider.GetUnlinkedExtentName(); var fromPart = VisitConstantExpressionNestClause(nestClause, subQuery.QueryModel.MainFromClause.FromExpression as ConstantExpression, genItemName); // Put any where clauses in the sub query in an ARRAY filtering clause using a LET statement var whereClauseString = string.Join(" AND ", subQuery.QueryModel.BodyClauses.OfType<WhereClause>() .Select(p => GetN1QlExpression(p.Predicate))); var letPart = new N1QlLetQueryPart() { ItemName = GetExtentName(nestClause), Value = string.Format("ARRAY {0} FOR {0} IN {1} WHEN {2} END", GetExtentName(subQuery.QueryModel.MainFromClause), genItemName, whereClauseString) }; _queryPartsAggregator.AddLetPart(letPart); if (!nestClause.IsLeftOuterNest) { // This is an INNER NEST, but the inner sequence filter is being applied after the NEST operation is done // So we need to put an additional filter to drop rows with an empty array result _queryPartsAggregator.AddWherePart("(ARRAY_LENGTH({0}) > 0)", letPart.ItemName); } return fromPart; default: throw new NotSupportedException("Unsupported Nest Inner Sequence"); } }
/// <summary> /// Visits an index nest join against either a constant expression of IBucketQueryable, or a subquery based on an IBucketQueryable /// </summary> /// <param name="joinClause">Join clause being visited</param> /// <param name="groupJoinClause">Group join clause being visited</param> /// <returns>N1QlFromQueryPart to be added to the QueryPartsAggregator. JoinType is defaulted to NEST.</returns> /// <remarks>The OuterKeySelector must be selecting the N1QlFunctions.Key of the OuterSequence</remarks> private N1QlFromQueryPart ParseIndexNestJoinClause(JoinClause joinClause, GroupJoinClause groupJoinClause) { if (joinClause.InnerSequence.NodeType == ExpressionType.Constant) { var clause = VisitConstantExpressionJoinClause(joinClause, joinClause.InnerSequence as ConstantExpression); clause.JoinType = "LEFT OUTER NEST"; _queryGenerationContext.ExtentNameProvider.LinkExtents(joinClause, groupJoinClause); return clause; } else if (joinClause.InnerSequence is SubQueryExpression) { var subQuery = (SubQueryExpression)joinClause.InnerSequence; if (subQuery.QueryModel.ResultOperators.Any() || subQuery.QueryModel.MainFromClause.FromExpression.NodeType != ExpressionType.Constant) { throw new NotSupportedException("Unsupported Join Inner Sequence"); } // Generate a temporary item name to use on the NEST statement, which we can then reference in the LET statement var fromPart = VisitConstantExpressionJoinClause(joinClause, subQuery.QueryModel.MainFromClause.FromExpression as ConstantExpression); fromPart.JoinType = "LEFT OUTER NEST"; // Put any where clauses in the sub query in an ARRAY filtering clause using a LET statement var whereClauseString = string.Join(" AND ", subQuery.QueryModel.BodyClauses.OfType<WhereClause>() .Select(p => GetN1QlExpression(p.Predicate))); var letPart = new N1QlLetQueryPart() { ItemName = GetExtentName(groupJoinClause), Value = string.Format("ARRAY {0} FOR {0} IN {1} WHEN {2} END", GetExtentName(subQuery.QueryModel.MainFromClause), GetExtentName(joinClause), whereClauseString) }; _queryPartsAggregator.AddLetPart(letPart); return fromPart; } else { throw new NotSupportedException("Unsupported Join Inner Sequence"); } }