Esempio n. 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");
            }
        }