Example #1
0
        /// <summary>Walks the subtree of this node and removes all nodes which were not marked projected.</summary>
        /// <remarks>Used to remove unnecessary expanded nodes.</remarks>
        internal void RemoveNonProjectedNodes()
        {
            for (int j = this.nodes.Count - 1; j >= 0; j--)
            {
                ExpandedProjectionNode expandedNode = this.nodes[j] as ExpandedProjectionNode;

                // Leave non-expanded properties there as they specify projections.
                if (expandedNode == null)
                {
                    continue;
                }

                // If we are to project entire subtree, leave all expanded nodes in as well
                // otherwise remove the expanded nodes which are not marked as projected.
                if (!this.projectSubtree && !expandedNode.ProjectionFound)
                {
                    // This removes the expandedNode from the tree (and all its children)
                    this.nodes.RemoveAt(j);
                }
                else
                {
                    expandedNode.RemoveNonProjectedNodes();
                }
            }
        }
 internal void MarkSubtreeAsProjected()
 {
     this.projectSubtree = true;
     this.projectAllImmediateProperties = false;
     foreach (ProjectionNode node in this.nodes)
     {
         ExpandedProjectionNode node2 = node as ExpandedProjectionNode;
         if (node2 != null)
         {
             node2.MarkSubtreeAsProjected();
         }
     }
 }
Example #3
0
 internal ExpandedProjectionNode AddExpandedNode(ExpandSegment segment)
 {
     ExpandedProjectionNode node = (ExpandedProjectionNode) this.FindNode(segment.Name);
     if ((node != null) && (node.Property == segment.ExpandedProperty))
     {
         if (segment.TargetResourceType.IsAssignableFrom(node.TargetResourceType))
         {
             node.TargetResourceType = segment.TargetResourceType;
         }
         return node;
     }
     node = new ExpandedProjectionNode(segment.Name, segment.ExpandedProperty, segment.TargetResourceType, segment.Container, segment.OrderingInfo, segment.Filter, null, (segment.Container.PageSize != 0) ? new int?(segment.Container.PageSize) : null, (segment.MaxResultsExpected != 0x7fffffff) ? new int?(segment.MaxResultsExpected) : null);
     this.AddNode(node);
     return node;
 }
        internal ExpandedProjectionNode AddExpandedNode(ExpandSegment segment)
        {
            ExpandedProjectionNode node = (ExpandedProjectionNode)this.FindNode(segment.Name);

            if ((node != null) && (node.Property == segment.ExpandedProperty))
            {
                if (segment.TargetResourceType.IsAssignableFrom(node.TargetResourceType))
                {
                    node.TargetResourceType = segment.TargetResourceType;
                }
                return(node);
            }
            node = new ExpandedProjectionNode(segment.Name, segment.ExpandedProperty, segment.TargetResourceType, segment.Container, segment.OrderingInfo, segment.Filter, null, (segment.Container.PageSize != 0) ? new int?(segment.Container.PageSize) : null, (segment.MaxResultsExpected != 0x7fffffff) ? new int?(segment.MaxResultsExpected) : null);
            this.AddNode(node);
            return(node);
        }
 internal void RemoveNonProjectedNodes()
 {
     for (int i = this.nodes.Count - 1; i >= 0; i--)
     {
         ExpandedProjectionNode node = this.nodes[i] as ExpandedProjectionNode;
         if (node != null)
         {
             if (!this.projectSubtree && !node.ProjectionFound)
             {
                 this.nodes.RemoveAt(i);
             }
             else
             {
                 node.RemoveNonProjectedNodes();
             }
         }
     }
 }
 private static bool ApplyPropertyToExistingNode(ProjectionNode existingNode, ResourceProperty property, System.Data.Services.Providers.ResourceType targetResourceType)
 {
     if (((property == null) || (existingNode.Property == null)) || (property == existingNode.Property))
     {
         ExpandedProjectionNode node = existingNode as ExpandedProjectionNode;
         if (targetResourceType.IsAssignableFrom(existingNode.TargetResourceType))
         {
             VerifyPropertyMismatchAndExpandSelectMismatchScenario(existingNode, property, targetResourceType, node != null);
             existingNode.TargetResourceType = targetResourceType;
             return(true);
         }
         if (existingNode.TargetResourceType.IsAssignableFrom(targetResourceType))
         {
             VerifyPropertyMismatchAndExpandSelectMismatchScenario(existingNode, property, targetResourceType, node != null);
             return(true);
         }
     }
     return(false);
 }
Example #7
0
        private static ExpandedProjectionNode ApplyProjectionForProperty(ExpandedProjectionNode parentNode, string propertyName, ResourceProperty property, ResourceType targetResourceType, bool lastPathSegment)
        {
            if (property != null)
            {
                switch (property.TypeKind)
                {
                    case ResourceTypeKind.ComplexType:
                        if (!lastPathSegment)
                        {
                            throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_ComplexPropertyAsInnerSelectSegment(targetResourceType.FullName, propertyName));
                        }
                        break;

                    case ResourceTypeKind.Primitive:
                        if (!lastPathSegment)
                        {
                            if (property.IsOfKind(ResourcePropertyKind.Stream))
                            {
                                throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_NamedStreamMustBeLastSegmentInSelect(propertyName));
                            }
                            throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_PrimitivePropertyUsedAsNavigationProperty(targetResourceType.FullName, propertyName));
                        }
                        break;

                    case ResourceTypeKind.Collection:
                        if (!lastPathSegment)
                        {
                            throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_CollectionPropertyAsInnerSelectSegment(targetResourceType.FullName, propertyName));
                        }
                        break;
                }
            }
            ExpandedProjectionNode node = parentNode.AddProjectionNode(propertyName, property, targetResourceType, lastPathSegment);
            if (lastPathSegment && (node != null))
            {
                node.ProjectionFound = true;
                node.MarkSubtreeAsProjected();
            }
            return node;
        }
        /// <summary>Recursive method which builds the $expand and $select paths for the specified node.</summary>
        /// <param name="parentPathSegments">List of path segments which lead up to this node. 
        /// So for example if the specified node is Orders/OrderDetails the list will contains two strings
        /// "Orders" and "OrderDetails".</param>
        /// <param name="projectionPaths">The result to which the projection paths are appended as a comma separated list.</param>
        /// <param name="expansionPaths">The result to which the expansion paths are appended as a comma separated list.</param>
        /// <param name="expandedNode">The node to inspect.</param>
        /// <param name="foundProjections">Out parameter which is set to true if there were some explicit projections on the inspected node.</param>
        /// <param name="foundExpansions">Our parameter which is set to true if there were some expansions on the inspected node.</param>
        private void BuildProjectionAndExpansionPathsForNode(
            List<string> parentPathSegments, 
            StringBuilder projectionPaths, 
            StringBuilder expansionPaths, 
            ExpandedProjectionNode expandedNode,
            out bool foundProjections,
            out bool foundExpansions)
        {
            foundProjections = false;
            foundExpansions = false;

            bool foundExpansionChild = false;
            bool foundProjectionChild = false;
            List<ExpandedProjectionNode> expandedChildrenNeededToBeProjected = new List<ExpandedProjectionNode>();
            foreach (ProjectionNode childNode in expandedNode.Nodes)
            {
                ExpandedProjectionNode expandedChildNode = childNode as ExpandedProjectionNode;
                if (expandedChildNode == null)
                {
                    // Explicitely project the property mentioned in this node
                    AppendProjectionOrExpansionPath(projectionPaths, parentPathSegments, childNode.PropertyName);
                    foundProjections = true;
                }
                else
                {
                    foundExpansions = true;

                    parentPathSegments.Add(expandedChildNode.PropertyName);
                    this.BuildProjectionAndExpansionPathsForNode(
                        parentPathSegments,
                        projectionPaths,
                        expansionPaths,
                        expandedChildNode,
                        out foundProjectionChild,
                        out foundExpansionChild);
                    parentPathSegments.RemoveAt(parentPathSegments.Count - 1);

                    // Add projection paths for this node if all its properties should be projected
                    if (expandedChildNode.ProjectAllProperties)
                    {
                        if (foundProjectionChild)
                        {
                            // There were some projections in our children, but this node requires all properties -> project *
                            AppendProjectionOrExpansionPath(projectionPaths, parentPathSegments, childNode.PropertyName + "/*");
                        }
                        else
                        {
                            // There were no projections underneath this node, so we need to "project" this node
                            // we just don't know yet if we need to project this one explicitly or if some parent will do it for us implicitly.
                            expandedChildrenNeededToBeProjected.Add(expandedChildNode);
                        }
                    }

                    foundProjections |= foundProjectionChild;

                    if (!foundExpansionChild)
                    {
                        // If there were no expansions in children, we need to add this node to expansion list
                        AppendProjectionOrExpansionPath(expansionPaths, parentPathSegments, childNode.PropertyName);
                    }
                }
            }

            if (!expandedNode.ProjectAllProperties || foundProjections)
            {
                // If we already projected some properties explicitely or this node does not want to project all properties 
                // and we have some expanded children which were not projected yet
                // we need to project those explicitely (as the other projections disable the "include all" for this node 
                // or we don't really want the "include all" anyway)
                foreach (ExpandedProjectionNode childToProject in expandedChildrenNeededToBeProjected)
                {
                    AppendProjectionOrExpansionPath(projectionPaths, parentPathSegments, childToProject.PropertyName);

                    // And since we're adding an explicit projection, mark us as using explicit projections
                    foundProjections = true;
                }
            }
        }
        /// <summary>
        /// Returns true if the subtree of expansions rooted in the specified <paramref name="expandedNode"/>
        /// contains either a filter or paging/maxresult constraint.
        /// </summary>
        /// <param name="expandedNode">The root of the expansions tree to inspect.</param>
        /// <returns>True if BasicExpandProvider should be used to process a query with this tree
        /// or false otherwise.</returns>
        private static bool ShouldUseBasicExpandProvider(ExpandedProjectionNode expandedNode)
        {
            foreach (ProjectionNode node in expandedNode.Nodes)
            {
                ExpandedProjectionNode childExpandedNode = node as ExpandedProjectionNode;
                if (childExpandedNode != null)
                {
                    if (childExpandedNode.HasFilterOrMaxResults)
                    {
                        return true;
                    }

                    if (ShouldUseBasicExpandProvider(childExpandedNode))
                    {
                        return true;
                    }
                }
            }

            return false;
        }
        internal void ApplyWildcardsAndSort(DataServiceProviderWrapper provider)
        {
            Func <ProjectionNode, bool> predicate = null;

            if (this.projectSubtree)
            {
                for (int i = this.nodes.Count - 1; i >= 0; i--)
                {
                    ExpandedProjectionNode node = this.nodes[i] as ExpandedProjectionNode;
                    if (node != null)
                    {
                        node.projectSubtree = true;
                        node.ApplyWildcardsAndSort(provider);
                    }
                    else
                    {
                        this.nodes.RemoveAt(i);
                    }
                }
                this.projectAllImmediateProperties = false;
                this.projectAllImmediateOperations = false;
            }
            else
            {
                for (int j = this.nodes.Count - 1; j >= 0; j--)
                {
                    ExpandedProjectionNode node2 = this.nodes[j] as ExpandedProjectionNode;
                    if (this.ProjectAllImmediateProperties && (node2 == null))
                    {
                        this.nodes.RemoveAt(j);
                    }
                    else if (node2 != null)
                    {
                        node2.ApplyWildcardsAndSort(provider);
                    }
                }
                if (this.nodes.Count > 0)
                {
                    List <System.Data.Services.Providers.ResourceType> resourceTypesInMetadataOrder = new List <System.Data.Services.Providers.ResourceType> {
                        this.ResourceType
                    };
                    if (predicate == null)
                    {
                        predicate = n => !System.Data.Services.Providers.ResourceType.CompareReferences(n.TargetResourceType, this.ResourceType);
                    }
                    List <ProjectionNode> source = this.nodes.Where <ProjectionNode>(predicate).ToList <ProjectionNode>();
                    if (source.Count > 0)
                    {
                        using (IEnumerator <System.Data.Services.Providers.ResourceType> enumerator = provider.GetDerivedTypes(this.ResourceType).GetEnumerator())
                        {
                            Func <ProjectionNode, bool> func = null;
                            System.Data.Services.Providers.ResourceType rt;
                            while (enumerator.MoveNext())
                            {
                                rt = enumerator.Current;
                                if (func == null)
                                {
                                    func = node => node.TargetResourceType == rt;
                                }
                                if (source.FirstOrDefault <ProjectionNode>(func) != null)
                                {
                                    resourceTypesInMetadataOrder.Add(rt);
                                }
                            }
                        }
                    }
                    this.nodes = SortNodes(this.nodes, resourceTypesInMetadataOrder);
                }
            }
        }
Example #11
0
        /// <summary>Removes duplicates from the tree caused by wildcards and sorts the projected properties.</summary>
        /// <remarks>
        /// Examples
        /// $select=Orders, Orders/ID           - get rid of the Orders/ID
        /// $select=Orders, Orders/*            - get rid of the Orders/*
        /// $select=Orders/*, Orders/ID         - get rid of the Orders/ID
        /// $select=Orders/*, Orders/OrderItems&amp;$expand=Orders - get rid of the Orders/OrderItems (it's redundant to *)
        /// $select=Orders/*, Orders/OrderItems&amp;$expand=Orders/OrderItems - leave as is, the Orders/OrderItems are expanded
        ///
        /// The sorting order is the same as the order in which the properties are enumerated on the owning type.
        /// This is to preserve the same order as if no projections occured.
        /// </remarks>
        internal void ApplyWildcardsAndSort()
        {
            // If this segment was marked to include entire subtree
            // simply remove all children which are not expanded
            // and propagate the information to all expanded children.
            if (this.projectSubtree)
            {
                for (int j = this.nodes.Count - 1; j >= 0; j--)
                {
                    ExpandedProjectionNode expandedNode = this.nodes[j] as ExpandedProjectionNode;
                    if (expandedNode != null)
                    {
                        expandedNode.projectSubtree = true;
                        expandedNode.ApplyWildcardsAndSort();
                    }
                    else
                    {
                        this.nodes.RemoveAt(j);
                    }
                }

                this.projectAllImmediateProperties = false;
                return;
            }

            for (int j = this.nodes.Count - 1; j >= 0; j--)
            {
                ExpandedProjectionNode expandedNode = this.nodes[j] as ExpandedProjectionNode;

                // If this node was marked to include all immediate properties,
                //   remove all children which are not expanded.
                //   That means they are either simple properties or nav. properties which
                //   are not going to be expanded anyway.
                if (this.ProjectAllImmediateProperties && expandedNode == null)
                {
                    this.nodes.RemoveAt(j);
                }
                else if (expandedNode != null)
                {
                    expandedNode.ApplyWildcardsAndSort();
                }
            }

            if (this.nodes.Count > 0)
            {
                // Sort the subsegments such that they have the same order as the properties
                //   on the owning resource type.
                ResourceType resourceType = this.ResourceType;

                List <ProjectionNode> existingNodes = this.nodes;
                this.nodes = new List <ProjectionNode>(existingNodes.Count);
                foreach (ResourceProperty property in resourceType.Properties)
                {
                    Debug.Assert(
                        existingNodes.Where(node => node.Property == property).Count() <= 1,
                        "Can't have more than one projection segment for a given property.");
                    ProjectionNode projectionNode = existingNodes.FirstOrDefault(
                        node => node.Property == property);
                    if (projectionNode != null)
                    {
                        this.nodes.Add(projectionNode);
                    }
                }

                // And then append any open properties sorted alphabetically
                // We sort these since we don't want client to be able to influence
                //   the server behavior unless abo----ely necessary.
                List <ProjectionNode> openPropertyProjectionNodes =
                    existingNodes.Where(node => node.Property == null).ToList();
                openPropertyProjectionNodes.Sort(new Comparison <ProjectionNode>((x, y) =>
                {
                    return(String.Compare(x.PropertyName, y.PropertyName, StringComparison.Ordinal));
                }));
                this.nodes.AddRange(openPropertyProjectionNodes);
                Debug.Assert(this.nodes.Count == existingNodes.Count, "We didn't sort all the properties.");
            }
        }