Example #1
0
        /// <summary>
        /// Visits a nest against a constant expression, which must be an IBucketQueryable implementation
        /// </summary>
        /// <param name="nestClause">Nest clause being visited</param>
        /// <param name="constantExpression">Constant expression that is the InnerSequence of the NestClause</param>
        /// <param name="itemName">Name to be used when referencing the data being nested</param>
        /// <returns>N1QlFromQueryPart to be added to the QueryPartsAggregator</returns>
        private N1QlFromQueryPart VisitConstantExpressionNestClause(NestClause nestClause, ConstantExpression constantExpression, string itemName)
        {
            string bucketName = null;

            if (constantExpression != null)
            {
                var bucketQueryable = constantExpression.Value as IBucketQueryable;
                if (bucketQueryable != null)
                {
                    bucketName = bucketQueryable.BucketName;
                }
            }

            if (bucketName == null)
            {
                throw new NotSupportedException("N1QL Nests Must Be Against IBucketQueryable");
            }

            return(new N1QlFromQueryPart()
            {
                Source = N1QlHelpers.EscapeIdentifier(bucketName),
                ItemName = itemName,
                OnKeys = GetN1QlExpression(nestClause.KeySelector),
                JoinType = nestClause.IsLeftOuterNest ? "LEFT OUTER NEST" : "INNER NEST"
            });
        }
Example #2
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");
            }
        }
Example #3
0
        public void VisitNestClause(NestClause nestClause, QueryModel queryModel, int index)
        {
            EnsureNotArraySubquery();

            _queryPartsAggregator.AddFromPart(ParseNestClause(nestClause));
        }