Ejemplo n.º 1
0
        /// <summary>
        /// Verify that the property referred by the existing node and the new segment are both open properties or declared properties
        /// and if the existing node is an expand node, make sure that the target resource types are the same.
        /// </summary>
        /// <param name="existingNode">Existing node with the same property name.</param>
        /// <param name="property">ResourceProperty instance for the property refered by the new segment.</param>
        /// <param name="targetResourceType">TargetResourceType for the new segment.</param>
        /// <param name="expandNode">true if the existingNode is an expand node.</param>
        private static void VerifyPropertyMismatchAndExpandSelectMismatchScenario(ProjectionNode existingNode, ResourceProperty property, ResourceType targetResourceType, bool expandNode)
        {
            Debug.Assert(
                existingNode.TargetResourceType.IsAssignableFrom(targetResourceType) ||
                targetResourceType.IsAssignableFrom(existingNode.TargetResourceType),
                "This method must be called if the existingNode and targetResourceType are in the same inheritance chain");
            Debug.Assert(!expandNode || existingNode is ExpandedProjectionNode, "If expandNode is true, then the existingNode must be an ExpandedProjectionNode");

            if (property != existingNode.Property)
            {
                // If the property are not the same - it means one of them must be null.
                // This is only possible if super type is open and the property resolves to an open property.
                Debug.Assert(property == null || existingNode.Property == null, "One of the properties must be null, since the types belong to the same inheritance chain, and cannot have different property instance from a given property name");

                // Currently we do not support scenarios where one refers to the open property on the supertype
                // and declared property on the sub type.
                throw DataServiceException.CreateBadRequestError(
                          Strings.RequestQueryProcessor_CannotSpecifyOpenPropertyAndDeclaredPropertyAtTheSameTime(
                              existingNode.PropertyName,
                              property == null ? targetResourceType.FullName : existingNode.TargetResourceType.FullName,
                              property == null ? existingNode.TargetResourceType.FullName : targetResourceType.FullName));
            }

            if (!ResourceType.CompareReferences(targetResourceType, existingNode.TargetResourceType) && expandNode)
            {
                // If expand and select are specified on the same property within a given type
                // hierarchy, currently we enforce that they must be specified on the same type
                throw DataServiceException.CreateBadRequestError(
                          Strings.RequestQueryProcessor_SelectAndExpandCannotBeSpecifiedTogether(existingNode.PropertyName));
            }
        }
Ejemplo n.º 2
0
        /// <summary>Adds a new child node to this node.</summary>
        /// <param name="node">The child node to add.</param>
        private void AddNode(ProjectionNode node)
        {
            Debug.Assert(node != null, "node != null");
            Debug.Assert(
                this.nodes.Count(
                    n => n.PropertyName == node.PropertyName &&
                    (n.TargetResourceType.IsAssignableFrom(node.TargetResourceType) || node.TargetResourceType.IsAssignableFrom(n.TargetResourceType))) == 0,
                "make sure there is no node with the same property name in the inheritance hierarchy");

            this.nodes.Add(node);

            ExpandedProjectionNode expandedNode = node as ExpandedProjectionNode;

            if (expandedNode != null)
            {
                this.hasExpandedPropertyOnDerivedType = this.hasExpandedPropertyOnDerivedType || (!ResourceType.CompareReferences(this.ResourceType, node.TargetResourceType));
            }
        }
Ejemplo n.º 3
0
        /// <summary>Removes duplicates from the tree caused by wildcards and sorts the projected properties.</summary>
        /// <param name="provider">underlying provider instance.</param>
        /// <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(DataServiceProviderWrapper provider)
        {
            // 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(provider);
                    }
                }

                this.projectAllImmediateProperties = false;
                this.projectAllImmediateOperations = 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(provider);
                }
            }

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

                // build the list of existing resource types that this query touches
                List <ResourceType> resourceTypes = new List <ResourceType>();
                resourceTypes.Add(this.ResourceType);

                // If we have one or more derived properties to expand or project,
                // we need to sort it based on the order in which the derived types
                // are return.
                List <ProjectionNode> derivedProjectionNodes = this.nodes.Where(n => !ResourceType.CompareReferences(n.TargetResourceType, this.ResourceType)).ToList();
                if (derivedProjectionNodes.Count > 0)
                {
                    foreach (ResourceType rt in provider.GetDerivedTypes(this.ResourceType))
                    {
                        if (derivedProjectionNodes.FirstOrDefault(node => node.TargetResourceType == rt) != null)
                        {
                            resourceTypes.Add(rt);
                        }
                    }
                }

#if DEBUG
                int count = this.nodes.Count;
#endif
                this.nodes = ExpandedProjectionNode.SortNodes(this.nodes, resourceTypes);
#if DEBUG
                Debug.Assert(this.nodes.Count == count, "We didn't sort all the properties.");
#endif
            }
        }