Beispiel #1
0
        /// <summary>
        /// Parses the segments of a path in the select clause.
        /// </summary>
        /// <param name="segments">The segments of the select path.</param>
        /// <param name="index">The index of the segment to parse.</param>
        private void ParsePathSegment(string[] segments, int index)
        {
            Debug.Assert(segments != null, "segments != null");
            Debug.Assert(index >= 0 && index < segments.Length, "index >= 0 && index < segments.Length");

            // NOTE: Each path is the name of a property or a series of property names
            //       separated by slash ('/'). The special star ('*') character is only supported at the end of a path.
            string currentSegment = segments[index].Trim();

            if (this.selectedProperties == null)
            {
                this.selectedProperties = CreateSelectedPropertiesHashSet();
            }

            bool isStar = string.CompareOrdinal(StarSegment, currentSegment) == 0;
            int  idxLP  = currentSegment.IndexOf('(');

            if (idxLP != -1 && IsValidExpandToken(currentSegment))
            {
                string token = currentSegment.Substring(0, idxLP);
                SelectedPropertiesNode childNode = this.EnsureChildAnnotation(token, /* isExpandedNavigationProperty */ true);
                childNode.edmModel = this.edmModel;

                if (idxLP < currentSegment.Length - 2)
                {
                    string clause = currentSegment.Substring(idxLP + 1, currentSegment.Length - idxLP - 2).Trim();
                    if (!String.IsNullOrEmpty(clause))
                    {
                        // Setup the edm model and structured type for the child node before start parsing the select clause.
                        IEdmNavigationProperty navProp = this.structuredType?.DeclaredNavigationProperties()
                                                         ?.SingleOrDefault(p => p.Name.Equals(token, StringComparison.Ordinal));

                        if (navProp?.Type != null)
                        {
                            // navigation property could be structural type or collection of structural type.
                            childNode.structuredType = navProp.Type.Definition.AsElementType() as IEdmStructuredType;
                        }

                        childNode.Parse(clause);
                    }
                }
                else
                {
                    childNode.selectionType = SelectionType.EntireSubtree;
                }
            }
            else
            {
                bool isLastSegment = index == segments.Length - 1;
                if (!isLastSegment)
                {
                    if (isStar)
                    {
                        throw new ODataException(ODataErrorStrings.SelectedPropertiesNode_StarSegmentNotLastSegment);
                    }

                    SelectedPropertiesNode childNode = this.EnsureChildAnnotation(currentSegment, false);
                    childNode.ParsePathSegment(segments, index + 1);
                }
                else
                {
                    this.selectedProperties.Add(currentSegment);
                }
            }

            this.hasWildcard |= isStar;
        }
Beispiel #2
0
        /// <summary>
        /// Recursively combines the left and right nodes. Used when there are type segments present in the select paths which
        /// causes there to be multiple children for the same property/navigation.
        /// </summary>
        /// <param name="left">The left node.</param>
        /// <param name="right">The right node.</param>
        /// <returns>The combined node.</returns>
        internal static SelectedPropertiesNode CombineNodes(SelectedPropertiesNode left, SelectedPropertiesNode right)
        {
            Debug.Assert(left != null, "left != null");
            Debug.Assert(right != null, "right != null");

            // if either one includes the entire subtree, then so does the result
            if (left.selectionType == SelectionType.EntireSubtree || right.selectionType == SelectionType.EntireSubtree)
            {
                return(new SelectedPropertiesNode(SelectionType.EntireSubtree));
            }

            // if the left hand side is empty, then use the right hand side
            if (left.selectionType == SelectionType.Empty)
            {
                // even if this is empty too, this all works
                return(right);
            }

            // likewise, if the right hand side is empty, use the left
            if (right.selectionType == SelectionType.Empty)
            {
                return(left);
            }

            Debug.Assert(left.selectionType == SelectionType.PartialSubtree, "left.selectionType == SelectionType.PartialSubtree");
            Debug.Assert(right.selectionType == SelectionType.PartialSubtree, "right.selectionType == SelectionType.PartialSubtree");

            var combined = new SelectedPropertiesNode(SelectionType.PartialSubtree)
            {
                hasWildcard = left.hasWildcard | right.hasWildcard
            };

            // copy over selected properties, combining as needed
            if (left.selectedProperties != null && right.selectedProperties != null)
            {
                combined.selectedProperties = CreateSelectedPropertiesHashSet(left.selectedProperties.AsEnumerable().Concat(right.selectedProperties));
            }
            else if (left.selectedProperties != null)
            {
                combined.selectedProperties = CreateSelectedPropertiesHashSet(left.selectedProperties);
            }
            else if (right.selectedProperties != null)
            {
                combined.selectedProperties = CreateSelectedPropertiesHashSet(right.selectedProperties);
            }

            // copy over children, combining as needed
            if (left.children != null && right.children != null)
            {
                combined.children = new Dictionary <string, SelectedPropertiesNode>(left.children);
                foreach (var child in right.children)
                {
                    SelectedPropertiesNode fromLeft;
                    if (combined.children.TryGetValue(child.Key, out fromLeft))
                    {
                        combined.children[child.Key] = CombineNodes(fromLeft, child.Value);
                    }
                    else
                    {
                        combined.children[child.Key] = child.Value;
                    }
                }
            }
            else if (left.children != null)
            {
                combined.children = new Dictionary <string, SelectedPropertiesNode>(left.children);
            }
            else if (right.children != null)
            {
                combined.children = new Dictionary <string, SelectedPropertiesNode>(right.children);
            }

            return(combined);
        }