/// <summary>Initializes a new RequestDescription based on an existing one.</summary>
        /// <param name="other">Other description to base new description on.</param>
        /// <param name="resultExpression">Query results for new request description.</param>
        /// <param name="rootProjectionNode">Projection segment describing the projections on the top level of the query.</param>
        internal RequestDescription(
            RequestDescription other,
            Expression resultExpression,
            RootProjectionNode rootProjectionNode)
        {
            Debug.Assert(
                resultExpression == null || other.SegmentInfos != null,
                "queryResults == null || other.SegmentInfos != null -- otherwise there isn't a segment in which to replace the query.");
            Debug.Assert(
                rootProjectionNode == null || resultExpression != null,
                "rootProjectionNode == null || queryResults != null -- otherwise there isn't a query to execute and expand");

            this.rootProjectionNode = rootProjectionNode;

            this.containerName = other.ContainerName;
            this.mimeType = other.MimeType;
            this.resultUri = other.ResultUri;
            this.segmentInfos = other.SegmentInfos;

            this.CopyFrom(other);

            if (resultExpression != null)
            {
                this.LastSegmentInfo.RequestExpression = resultExpression;
            }
        }
        /// <summary>
        /// Performs a depth-first walk down the expand tree, copying and adding to the current path as it goes. When the bottom of a path is reached, the path is added to the overall set of paths.
        /// </summary>
        /// <param name="currentPath">The current path so far for this depth-first traversal of the tree. Starts out null.</param>
        /// <param name="currentNode">The current node of the expand tree.</param>
        /// <param name="rootNode">The root node of the expand tree.</param>
        private void ExtractExpandPathSegmentCollections(ExpandSegmentCollection currentPath, ExpandedProjectionNode currentNode, RootProjectionNode rootNode)
        {
            ExpandSegmentCollection nextPath = null;
            foreach (ExpandedNavigationSelectItem expandItem in currentNode.SelectExpandClause.SelectedItems.OfType<ExpandedNavigationSelectItem>())
            {
                rootNode.ExpansionsSpecified = true;

                if (currentPath == null)
                {
                    nextPath = new ExpandSegmentCollection();
                }
                else
                {
                    // create a copy of the current path.
                    nextPath = new ExpandSegmentCollection(currentPath.Count);
                    nextPath.AddRange(currentPath);
                }

                var segment = this.CreateExpandSegment(expandItem, currentNode.ResourceType);
                nextPath.Add(segment);
                ExpandedProjectionNode childNode = currentNode.AddExpandedNode(segment, expandItem.SelectAndExpand);

                // if there are any derived expansions in the tree, set the rootNode.DerivedExpansionsSpecified to true.
                if (currentNode.HasExpandedPropertyOnDerivedType)
                {
                    rootNode.ExpansionOnDerivedTypesSpecified = true;
                }

                this.ExtractExpandPathSegmentCollections(nextPath, childNode, rootNode);
            }

            if (nextPath == null && currentPath != null)
            {
                this.expandPaths.Add(currentPath);
            }
        }
        /// <summary>Initializes a new <see cref="RequestQueryProcessor"/> instance.</summary>
        /// <param name="service">Service with data and configuration.</param>
        /// <param name="description">Description for request processed so far.</param>
        private RequestQueryProcessor(IDataService service, RequestDescription description)
        {
            this.service = service;
            this.description = description;
#if DEBUG
            this.orderApplied = false;
#endif
            this.skipCount = null;
            this.topCount = null;
            this.queryExpression = description.RequestExpression;

            this.setQueryApplicable = (description.TargetKind == RequestTargetKind.Resource && !description.IsSingleResult) ||
                                       description.CountOption == RequestQueryCountOption.CountSegment;

            // Server Driven Paging is not considered for the following cases: 
            // 1. Top level result is not or resource type or it is a single valued result.
            // 2. $count segment provided.
            // 3. Non-GET requests do not honor SDP.
            // 4. Only exception for Non-GET requests is if the request is coming from a Service
            //    operation that returns a set of result values of entity type.
            this.pagingApplicable = (description.TargetKind == RequestTargetKind.Resource && !description.IsSingleResult) &&
                                    (description.CountOption != RequestQueryCountOption.CountSegment) &&
                                    !description.IsRequestForEnumServiceOperation &&
                                    (service.OperationContext.RequestMessage.HttpVerb.IsQuery() || description.SegmentInfos[0].TargetSource == RequestTargetSource.ServiceOperation);

            this.appliedCustomPaging = false;

            this.rootProjectionNode = null;
            this.topLevelOrderingInfo = null;

            this.skipTokenExpressionBuilder = new SkipTokenExpressionBuilder(NodeToExpressionTranslator.Create(this.service, description, Expression.Parameter(typeof(object))));
        }
        /// <summary>Gets the root projection node or creates one if no one exists yet.</summary>
        /// <returns>The root node of the projection tree.</returns>
        private RootProjectionNode GetRootProjectionNode()
        {
            if (this.rootProjectionNode == null)
            {
                // Build the root of the projection and expansion tree
                this.rootProjectionNode = new RootProjectionNode(
                    this.description.LastSegmentInfo.TargetResourceSet,
                    this.topLevelOrderingInfo,
                    null,
                    this.skipCount,
                    this.topCount,
                    null,
                    this.expandPaths,
                    this.description.TargetResourceType,
                    this.description.ExpandAndSelect.Clause);
            }

            return this.rootProjectionNode;
        }