Пример #1
0
        /// <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");
            }
        }
Пример #2
0
 public void AddLetPart(N1QlLetQueryPart letPart)
 {
     LetParts.Add(letPart);
 }
 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");
            }
        }