private void AddNode(ProjectionNode node)
 {
     this.nodes.Add(node);
     if (node is ExpandedProjectionNode)
     {
         this.hasExpandedPropertyOnDerivedType = this.hasExpandedPropertyOnDerivedType || !System.Data.Services.Providers.ResourceType.CompareReferences(this.ResourceType, node.TargetResourceType);
     }
 }
示例#2
0
 private void AddNode(ProjectionNode node)
 {
     this.nodes.Add(node);
     if (node is ExpandedProjectionNode)
     {
         this.hasExpandedPropertyOnDerivedType = this.hasExpandedPropertyOnDerivedType || !System.Data.Services.Providers.ResourceType.CompareReferences(this.ResourceType, node.TargetResourceType);
     }
 }
 private static void VerifyPropertyMismatchAndExpandSelectMismatchScenario(ProjectionNode existingNode, ResourceProperty property, System.Data.Services.Providers.ResourceType targetResourceType, bool expandNode)
 {
     if (property != existingNode.Property)
     {
         throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_CannotSpecifyOpenPropertyAndDeclaredPropertyAtTheSameTime(existingNode.PropertyName, (property == null) ? targetResourceType.FullName : existingNode.TargetResourceType.FullName, (property == null) ? existingNode.TargetResourceType.FullName : targetResourceType.FullName));
     }
     if (!System.Data.Services.Providers.ResourceType.CompareReferences(targetResourceType, existingNode.TargetResourceType) && expandNode)
     {
         throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_SelectAndExpandCannotBeSpecifiedTogether(existingNode.PropertyName));
     }
 }
示例#4
0
 internal ExpandedProjectionNode AddProjectionNode(string propertyName, ResourceProperty property, System.Data.Services.Providers.ResourceType targetResourceType, bool lastPathSegment)
 {
     ProjectionNode existingNode = this.FindNode(propertyName);
     if ((existingNode == null) || !ApplyPropertyToExistingNode(existingNode, property, targetResourceType))
     {
         if (!lastPathSegment)
         {
             throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_ProjectedPropertyWithoutMatchingExpand(base.PropertyName));
         }
         existingNode = new ProjectionNode(propertyName, property, targetResourceType);
         this.AddNode(existingNode);
     }
     return (existingNode as ExpandedProjectionNode);
 }
        internal ExpandedProjectionNode AddProjectionNode(string propertyName, ResourceProperty property, System.Data.Services.Providers.ResourceType targetResourceType, bool lastPathSegment)
        {
            ProjectionNode existingNode = this.FindNode(propertyName);

            if ((existingNode == null) || !ApplyPropertyToExistingNode(existingNode, property, targetResourceType))
            {
                if (!lastPathSegment)
                {
                    throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_ProjectedPropertyWithoutMatchingExpand(base.PropertyName));
                }
                existingNode = new ProjectionNode(propertyName, property, targetResourceType);
                this.AddNode(existingNode);
            }
            return(existingNode as ExpandedProjectionNode);
        }
 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);
 }
        private static List <ProjectionNode> SortNodes(List <ProjectionNode> existingNodes, List <System.Data.Services.Providers.ResourceType> resourceTypesInMetadataOrder)
        {
            List <ProjectionNode> list = new List <ProjectionNode>(existingNodes.Count);

            using (List <System.Data.Services.Providers.ResourceType> .Enumerator enumerator = resourceTypesInMetadataOrder.GetEnumerator())
            {
                System.Data.Services.Providers.ResourceType resourceType;
                while (enumerator.MoveNext())
                {
                    resourceType = enumerator.Current;
                    using (IEnumerator <ResourceProperty> enumerator2 = resourceType.Properties.GetEnumerator())
                    {
                        Func <ProjectionNode, bool> predicate = null;
                        ResourceProperty            property;
                        while (enumerator2.MoveNext())
                        {
                            property = enumerator2.Current;
                            if (predicate == null)
                            {
                                predicate = node => (node.Property == property) && (node.TargetResourceType == resourceType);
                            }
                            ProjectionNode item = existingNodes.FirstOrDefault <ProjectionNode>(predicate);
                            if (item != null)
                            {
                                list.Add(item);
                                existingNodes.Remove(item);
                            }
                        }
                        continue;
                    }
                }
            }
            List <ProjectionNode> collection = (from node in existingNodes
                                                where node.Property == null
                                                select node).ToList <ProjectionNode>();

            collection.Sort((Comparison <ProjectionNode>)((x, y) => string.Compare(x.PropertyName, y.PropertyName, StringComparison.Ordinal)));
            list.AddRange(collection);
            return(list);
        }
示例#8
0
 /// <summary>Applies expansions and projections to the specified <paramref name="source"/>.</summary>
 /// <param name="source"><see cref="IQueryable"/> object to expand and apply projections to.</param>
 /// <param name="projection">The root node of the tree which describes
 /// the projections and expansions to be applied to the <paramref name="source"/>.</param>
 /// <returns>
 /// An <see cref="IQueryable"/> object, with the results including 
 /// the expansions and projections specified in <paramref name="projection"/>. 
 /// </returns>
 /// <remarks>
 /// The returned <see cref="IQueryable"/> may implement the <see cref="IExpandedResult"/> interface 
 /// to provide enumerable objects for the expansions; otherwise, the expanded
 /// information is expected to be found directly in the enumerated objects. If paging is 
 /// requested by providing a non-empty list in <paramref name="projection"/>.OrderingInfo then
 /// it is expected that the topmost <see cref="IExpandedResult"/> would have a $skiptoken property 
 /// which will be an <see cref="IExpandedResult"/> in itself and each of it's sub-properties will
 /// be named SkipTokenPropertyXX where XX represents numbers in increasing order starting from 0. Each of 
 /// SkipTokenPropertyXX properties will be used to generated the $skiptoken to support paging.
 /// If projections are required, the provider may choose to return <see cref="IQueryable"/>
 /// which returns instances of <see cref="IProjectedResult"/>. In that case property values are determined
 /// by calling the <see cref="IProjectedResult.GetProjectedPropertyValue"/> method instead of
 /// accessing properties of the returned object directly.
 /// If both expansion and projections are required, the provider may choose to return <see cref="IQueryable"/>
 /// of <see cref="IExpandedResult"/> which in turn returns <see cref="IProjectedResult"/> from its
 /// <see cref="IExpandedResult.ExpandedElement"/> property.
 /// </remarks>
 public abstract IQueryable ApplyProjections(
     IQueryable source,
     ProjectionNode projection);
示例#9
0
 /// <summary>Adds a new child node to this node.</summary>
 /// <param name="node">The child node to add.</param>
 internal void AddNode(ProjectionNode node)
 {
     Debug.Assert(node != null, "node != null");
     Debug.Assert(this.FindNode(node.PropertyName) == null, "Trying to add a duplicate node.");
     this.nodes.Add(node);
 }
示例#10
0
 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;
 }
示例#11
0
 private static void VerifyPropertyMismatchAndExpandSelectMismatchScenario(ProjectionNode existingNode, ResourceProperty property, System.Data.Services.Providers.ResourceType targetResourceType, bool expandNode)
 {
     if (property != existingNode.Property)
     {
         throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_CannotSpecifyOpenPropertyAndDeclaredPropertyAtTheSameTime(existingNode.PropertyName, (property == null) ? targetResourceType.FullName : existingNode.TargetResourceType.FullName, (property == null) ? existingNode.TargetResourceType.FullName : targetResourceType.FullName));
     }
     if (!System.Data.Services.Providers.ResourceType.CompareReferences(targetResourceType, existingNode.TargetResourceType) && expandNode)
     {
         throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_SelectAndExpandCannotBeSpecifiedTogether(existingNode.PropertyName));
     }
 }
示例#12
0
        /// <summary>Applies expansions and projections to the specified <paramref name="source"/>.</summary>
        /// <param name="source"><see cref="IQueryable"/> object to expand and apply projections to.</param>
        /// <param name="projection">The root node of the tree which describes
        /// the projections and expansions to be applied to the <paramref name="source"/>.</param>
        /// <returns>
        /// An <see cref="IQueryable"/> object, with the results including 
        /// the expansions and projections specified in <paramref name="projection"/>. 
        /// </returns>
        /// <remarks>
        /// The returned <see cref="IQueryable"/> may implement the <see cref="IExpandedResult"/> interface 
        /// to provide enumerable objects for the expansions; otherwise, the expanded
        /// information is expected to be found directly in the enumerated objects. If paging is 
        /// requested by providing a non-empty list in <paramref name="projection"/>.OrderingInfo then
        /// it is expected that the topmost <see cref="IExpandedResult"/> would have a $skiptoken property 
        /// which will be an <see cref="IExpandedResult"/> in itself and each of it's sub-properties will
        /// be named SkipTokenPropertyXX where XX represents numbers in increasing order starting from 0. Each of 
        /// SkipTokenPropertyXX properties will be used to generated the $skiptoken to support paging.
        /// If projections are required, the provider may choose to return <see cref="IQueryable"/>
        /// which returns instances of <see cref="IProjectedResult"/>. In that case property values are determined
        /// by calling the <see cref="IProjectedResult.GetProjectedPropertyValue"/> method instead of
        /// accessing properties of the returned object directly.
        /// If both expansion and projections are required, the provider may choose to return <see cref="IQueryable"/>
        /// of <see cref="IExpandedResult"/> which in turn returns <see cref="IProjectedResult"/> from its
        /// <see cref="IExpandedResult.ExpandedElement"/> property.
        /// </remarks>
        public override IQueryable ApplyProjections(
            IQueryable source,
            ProjectionNode projection)
        {
            Debug.Assert(projection is RootProjectionNode, "We always get the special root node.");
            RootProjectionNode rootNode = (RootProjectionNode)projection;
            Debug.Assert(rootNode.OrderingInfo != null, "We always get non-null OrderingInfo");
            bool useBasicExpandProvider = ShouldUseBasicExpandProvider(rootNode);

            // We need the $skiptoken for top level result if it is paged, hence we need to use ApplyExpansions in that case
            if (useBasicExpandProvider || rootNode.OrderingInfo.IsPaged || rootNode.ProjectionsSpecified)
            {
                return new BasicExpandProvider(this.ProviderWrapper, true, true).ApplyProjections(source, projection);
            }

            // This pass-through implementation is appropriate for providers that fault-in on demand.
            return BasicExpandProvider.ApplyOrderSkipTakeOnTopLevelResultBeforeProjections(
                source,
                rootNode.OrderingInfo,
                rootNode.SkipCount,
                rootNode.TakeCount);
        }
 /// <summary>Applies expansions and projections to the specified <paramref name="source"/>.</summary>
 /// <param name="source"><see cref="IQueryable"/> object to expand and apply projections to.</param>
 /// <param name="projection">The root node of the tree which describes
 /// the projections and expansions to be applied to the <paramref name="source"/>.</param>
 /// <returns>
 /// An <see cref="IQueryable"/> object, with the results including
 /// the expansions and projections specified in <paramref name="projection"/>.
 /// </returns>
 /// <remarks>
 /// The returned <see cref="IQueryable"/> may implement the <see cref="IExpandedResult"/> interface
 /// to provide enumerable objects for the expansions; otherwise, the expanded
 /// information is expected to be found directly in the enumerated objects. If paging is
 /// requested by providing a non-empty list in <paramref name="projection"/>.OrderingInfo then
 /// it is expected that the topmost <see cref="IExpandedResult"/> would have a $skiptoken property
 /// which will be an <see cref="IExpandedResult"/> in itself and each of it's sub-properties will
 /// be named SkipTokenPropertyXX where XX represents numbers in increasing order starting from 0. Each of
 /// SkipTokenPropertyXX properties will be used to generated the $skiptoken to support paging.
 /// If projections are required, the provider may choose to return <see cref="IQueryable"/>
 /// which returns instances of <see cref="IProjectedResult"/>. In that case property values are determined
 /// by calling the <see cref="IProjectedResult.GetProjectedPropertyValue"/> method instead of
 /// accessing properties of the returned object directly.
 /// If both expansion and projections are required, the provider may choose to return <see cref="IQueryable"/>
 /// of <see cref="IExpandedResult"/> which in turn returns <see cref="IProjectedResult"/> from its
 /// <see cref="IExpandedResult.ExpandedElement"/> property.
 /// </remarks>
 public abstract IQueryable ApplyProjections(
     IQueryable source,
     ProjectionNode projection);
示例#14
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.");
            }
        }
示例#15
0
 /// <summary>Adds a new child node to this node.</summary>
 /// <param name="node">The child node to add.</param>
 internal void AddNode(ProjectionNode node)
 {
     Debug.Assert(node != null, "node != null");
     Debug.Assert(this.FindNode(node.PropertyName) == null, "Trying to add a duplicate node.");
     this.nodes.Add(node);
 }