/// <summary>
        /// Build the $select item, it maybe $select=complex/abc, $select=abc, $select=nav, etc.
        /// </summary>
        /// <param name="pathSelectItem">The expanded reference select item.</param>
        /// <param name="currentLevelPropertiesInclude">The current properties to include at current level.</param>
        /// <param name="computedProperties">The computed properties.</param>
        /// <param name="structuralTypeInfo">The structural type properties.</param>
        private void BuildSelectItem(PathSelectItem pathSelectItem,
                                     IDictionary <IEdmStructuralProperty, SelectExpandIncludedProperty> currentLevelPropertiesInclude,
                                     ISet <string> computedProperties,
                                     EdmStructuralTypeInfo structuralTypeInfo)
        {
            Contract.Assert(pathSelectItem != null && pathSelectItem.SelectedPath != null);
            Contract.Assert(currentLevelPropertiesInclude != null);
            Contract.Assert(structuralTypeInfo != null);

            // Verify and process the $select=abc/xyz/....
            ODataSelectPath          selectPath = pathSelectItem.SelectedPath;
            IList <ODataPathSegment> remainingSegments;
            ODataPathSegment         segment = selectPath.GetFirstNonTypeCastSegment(out remainingSegments);

            PropertySegment firstPropertySegment = segment as PropertySegment;

            if (firstPropertySegment != null)
            {
                if (structuralTypeInfo.IsStructuralPropertyDefined(firstPropertySegment.Property))
                {
                    // $select=abc/xyz/...
                    SelectExpandIncludedProperty newPropertySelectItem;
                    if (!currentLevelPropertiesInclude.TryGetValue(firstPropertySegment.Property, out newPropertySelectItem))
                    {
                        newPropertySelectItem = new SelectExpandIncludedProperty(firstPropertySegment);
                        currentLevelPropertiesInclude[firstPropertySegment.Property] = newPropertySelectItem;
                    }

                    newPropertySelectItem.AddSubSelectItem(remainingSegments, pathSelectItem);
                }

                return;
            }

            // If the first segment is not a property segment,
            // that segment must be the last segment, so the remaining segments should be null.
            Contract.Assert(remainingSegments == null);

            NavigationPropertySegment navigationSegment = segment as NavigationPropertySegment;

            if (navigationSegment != null)
            {
                // for example: $select=NavigationProperty or $select=NS.VipCustomer/VipNav
                if (structuralTypeInfo.IsNavigationPropertyDefined(navigationSegment.NavigationProperty))
                {
                    if (SelectedNavigationProperties == null)
                    {
                        SelectedNavigationProperties = new HashSet <IEdmNavigationProperty>();
                    }

                    SelectedNavigationProperties.Add(navigationSegment.NavigationProperty);
                }

                return;
            }

            OperationSegment operationSegment = segment as OperationSegment;

            if (operationSegment != null)
            {
                // for example: $select=NS.Operation, or, $select=NS.VipCustomer/NS.Operation
                AddOperations(operationSegment, structuralTypeInfo.AllActions, structuralTypeInfo.AllFunctions);
                return;
            }

            DynamicPathSegment dynamicPathSegment = segment as DynamicPathSegment;

            if (dynamicPathSegment != null)
            {
                if (computedProperties != null && computedProperties.Contains(dynamicPathSegment.Identifier))
                {
                    // If it's from $compute
                    SelectedComputedProperties.Add(dynamicPathSegment.Identifier);
                }
                else
                {
                    // or it's from dynamic property
                    if (SelectedDynamicProperties == null)
                    {
                        SelectedDynamicProperties = new HashSet <string>();
                    }

                    SelectedDynamicProperties.Add(dynamicPathSegment.Identifier);
                }
                return;
            }

            // In fact, we should never be here, because it's verified above
            throw new ODataException(Error.Format(SRResources.SelectionTypeNotSupported, segment.GetType().Name));
        }
        /// <summary>
        /// Build $select and $expand clause
        /// </summary>
        /// <param name="selectExpandClause">The select expand clause</param>
        /// <param name="computedProperties">The structural type properties.</param>
        /// <param name="structuralTypeInfo">The computed properties.</param>
        private void BuildSelectExpand(SelectExpandClause selectExpandClause, ISet <string> computedProperties, EdmStructuralTypeInfo structuralTypeInfo)
        {
            Contract.Assert(selectExpandClause != null);
            Contract.Assert(structuralTypeInfo != null);

            var currentLevelPropertiesInclude = new Dictionary <IEdmStructuralProperty, SelectExpandIncludedProperty>();

            // Explicitly set SelectAllDynamicProperties as false,
            // Below will re-set it as true if it meets the select all condition.
            SelectAllDynamicProperties = false;
            foreach (SelectItem selectItem in selectExpandClause.SelectedItems)
            {
                // $expand=...
                ExpandedReferenceSelectItem expandReferenceItem = selectItem as ExpandedReferenceSelectItem;
                if (expandReferenceItem != null)
                {
                    BuildExpandItem(expandReferenceItem, currentLevelPropertiesInclude, structuralTypeInfo);
                    continue;
                }

                PathSelectItem pathSelectItem = selectItem as PathSelectItem;
                if (pathSelectItem != null)
                {
                    // $select=abc/.../xyz
                    BuildSelectItem(pathSelectItem, currentLevelPropertiesInclude, computedProperties, structuralTypeInfo);
                    continue;
                }

                WildcardSelectItem wildCardSelectItem = selectItem as WildcardSelectItem;
                if (wildCardSelectItem != null)
                {
                    // $select=*
                    MergeAllStructuralProperties(structuralTypeInfo.AllStructuralProperties, currentLevelPropertiesInclude);
                    MergeSelectedNavigationProperties(structuralTypeInfo.AllNavigationProperties);
                    SelectAllDynamicProperties = true;

                    if (computedProperties != null)
                    {
                        foreach (var property in computedProperties)
                        {
                            SelectedComputedProperties.Add(property);
                        }
                    }
                    continue;
                }

                NamespaceQualifiedWildcardSelectItem wildCardActionSelection = selectItem as NamespaceQualifiedWildcardSelectItem;
                if (wildCardActionSelection != null)
                {
                    // $select=NS.*
                    AddNamespaceWildcardOperation(wildCardActionSelection, structuralTypeInfo.AllActions, structuralTypeInfo.AllFunctions);
                    continue;
                }

                throw new ODataException(Error.Format(SRResources.SelectionTypeNotSupported, selectItem.GetType().Name));
            }

            if (selectExpandClause.AllSelected)
            {
                MergeAllStructuralProperties(structuralTypeInfo.AllStructuralProperties, currentLevelPropertiesInclude);
                MergeSelectedNavigationProperties(structuralTypeInfo.AllNavigationProperties);
                MergeSelectedAction(structuralTypeInfo.AllActions);
                MergeSelectedFunction(structuralTypeInfo.AllFunctions);
                SelectAllDynamicProperties = true;
            }

            // to make sure the structural properties are in the same order defined in the type.
            if (structuralTypeInfo.AllStructuralProperties != null)
            {
                foreach (var structuralProperty in structuralTypeInfo.AllStructuralProperties)
                {
                    SelectExpandIncludedProperty includeProperty;
                    if (!currentLevelPropertiesInclude.TryGetValue(structuralProperty, out includeProperty))
                    {
                        continue;
                    }

                    PathSelectItem pathSelectItem = includeProperty == null ? null : includeProperty.ToPathSelectItem();
                    AddStructuralProperty(structuralProperty, pathSelectItem);
                }
            }
        }