public void Ctor_ThatBuildsNestedContext_CopiesProperties()
        {
            // Arrange
            CustomersModelWithInheritance model = new CustomersModelWithInheritance();
            ODataSerializerContext context = new ODataSerializerContext
            {
                EntitySet = model.Customers,
                MetadataLevel = ODataMetadataLevel.FullMetadata,
                Model = model.Model,
                Path = new ODataPath(),
                Request = new HttpRequestMessage(),
                RootElementName = "somename",
                SelectExpandClause = new SelectExpandClause(new SelectItem[0], allSelected: true),
                SkipExpensiveAvailabilityChecks = true,
                Url = new UrlHelper()
            };
            EntityInstanceContext entity = new EntityInstanceContext { SerializerContext = context };
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[0], allSelected: true);
            IEdmNavigationProperty navProp = model.Customer.NavigationProperties().First();

            // Act
            ODataSerializerContext nestedContext = new ODataSerializerContext(entity, selectExpand, navProp);

            // Assert
            Assert.Equal(context.MetadataLevel, nestedContext.MetadataLevel);
            Assert.Same(context.Model, nestedContext.Model);
            Assert.Same(context.Path, nestedContext.Path);
            Assert.Same(context.Request, nestedContext.Request);
            Assert.Equal(context.RootElementName, nestedContext.RootElementName);
            Assert.Equal(context.SkipExpensiveAvailabilityChecks, nestedContext.SkipExpensiveAvailabilityChecks);
            Assert.Same(context.Url, nestedContext.Url);
        }
        private static void ValidateDepth(SelectExpandClause selectExpand, int maxDepth)
        {
            // do a DFS to see if there is any node that is too deep.
            Stack<Tuple<int, SelectExpandClause>> nodesToVisit = new Stack<Tuple<int, SelectExpandClause>>();
            nodesToVisit.Push(Tuple.Create(0, selectExpand));
            while (nodesToVisit.Count > 0)
            {
                Tuple<int, SelectExpandClause> tuple = nodesToVisit.Pop();
                int currentDepth = tuple.Item1;
                SelectExpandClause currentNode = tuple.Item2;

                if (currentNode.Expansion != null)
                {
                    IEnumerable<ExpandItem> expandItems = currentNode.Expansion.ExpandItems;
                    if (expandItems.Any() && currentDepth == maxDepth)
                    {
                        throw new ODataException(
                            Error.Format(SRResources.MaxExpandDepthExceeded, maxDepth, "MaxExpansionDepth"));
                    }

                    IEnumerable<SelectExpandClause> children = expandItems.Select(i => i.SelectExpandOption);
                    foreach (SelectExpandClause child in children)
                    {
                        nodesToVisit.Push(Tuple.Create(currentDepth + 1, child));
                    }
                }
            }
        }
        public void Ctor_ForNestedContext_ThrowsArgumentNull_Entity()
        {
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[0], allSelected: true);
            IEdmNavigationProperty navProp = new Mock<IEdmNavigationProperty>().Object;

            Assert.ThrowsArgumentNull(
                () => new ODataSerializerContext(entity: null, selectExpandClause: selectExpand, navigationProperty: navProp), "entity");
        }
        public void Ctor_ThatBuildsNestedContext_InitializesRightValues()
        {
            // Arrange
            CustomersModelWithInheritance model = new CustomersModelWithInheritance();
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[0], allSelected: true);
            IEdmNavigationProperty navProp = model.Customer.NavigationProperties().First();
            ODataSerializerContext context = new ODataSerializerContext { EntitySet = model.Customers, Model = model.Model };
            EntityInstanceContext entity = new EntityInstanceContext { SerializerContext = context };

            // Act
            ODataSerializerContext nestedContext = new ODataSerializerContext(entity, selectExpand, navProp);

            // Assert
            Assert.Same(entity, nestedContext.ExpandedEntity);
            Assert.Same(navProp, nestedContext.NavigationProperty);
            Assert.Same(selectExpand, nestedContext.SelectExpandClause);
            Assert.Same(model.Orders, nestedContext.EntitySet);
        }
        /// <summary>
        /// Creates a new instance of the <see cref="SelectExpandNode"/> class describing the set of structural properties,
        /// navigation properties, and actions to select and expand for the given <paramref name="selectExpandClause"/>.
        /// </summary>
        /// <param name="selectExpandClause">The parsed $select and $expand query options.</param>
        /// <param name="entityType">The entity type of the entry that would be written.</param>
        /// <param name="model">The <see cref="IEdmModel"/> that contains the given entity type.</param>
        public SelectExpandNode(SelectExpandClause selectExpandClause, IEdmEntityTypeReference entityType, IEdmModel model)
            : this()
        {
            if (entityType == null)
            {
                throw Error.ArgumentNull("entityType");
            }
            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            HashSet<IEdmStructuralProperty> allStructuralProperties = new HashSet<IEdmStructuralProperty>(entityType.StructuralProperties());
            HashSet<IEdmNavigationProperty> allNavigationProperties = new HashSet<IEdmNavigationProperty>(entityType.NavigationProperties());
            HashSet<IEdmFunctionImport> allActions = new HashSet<IEdmFunctionImport>(model.GetAvailableProcedures(entityType.EntityDefinition()));

            if (selectExpandClause == null)
            {
                SelectedStructuralProperties = allStructuralProperties;
                SelectedNavigationProperties = allNavigationProperties;
                SelectedActions = allActions;
            }
            else
            {
                if (selectExpandClause.AllSelected)
                {
                    SelectedStructuralProperties = allStructuralProperties;
                    SelectedNavigationProperties = allNavigationProperties;
                    SelectedActions = allActions;
                }
                else
                {
                    BuildSelections(selectExpandClause, allStructuralProperties, allNavigationProperties, allActions);
                }

                BuildExpansions(selectExpandClause, allNavigationProperties);

                // remove expanded navigation properties from the selected navigation properties.
                SelectedNavigationProperties.ExceptWith(ExpandedNavigationProperties.Keys);
            }
        }
예제 #6
0
        /// <summary>
        /// Builds the <see cref="SelectExpandNode"/> describing the set of structural properties and navigation properties and actions to select
        /// and navigation properties to expand while writing an entry of type <paramref name="entityType"/> for the given 
        /// <paramref name="selectExpandClause"/>.
        /// </summary>
        /// <param name="selectExpandClause">The parsed $select and $expand query options.</param>
        /// <param name="entityType">The entity type of the entry that would be written.</param>
        /// <param name="model">The <see cref="IEdmModel"/> that contains the given entity type.</param>
        /// <returns>The built <see cref="SelectExpandNode"/>.</returns>
        public static SelectExpandNode BuildSelectExpandNode(SelectExpandClause selectExpandClause, IEdmEntityTypeReference entityType, IEdmModel model)
        {
            if (entityType == null)
            {
                throw Error.ArgumentNull("entityType");
            }
            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            SelectExpandNode selectExpandNode = new SelectExpandNode();
            if (selectExpandClause != null && selectExpandClause.Expansion != null)
            {
                selectExpandNode.BuildExpansions(selectExpandClause.Expansion, entityType);
            }
            selectExpandNode.BuildSelections(selectExpandClause == null ? null : selectExpandClause.Selection, entityType, model);

            // remove expanded navigation properties from the selected navigation properties.
            IEnumerable<IEdmNavigationProperty> expandedNavigationProperties = selectExpandNode.ExpandedNavigationProperties.Keys;
            selectExpandNode.SelectedNavigationProperties.ExceptWith(expandedNavigationProperties);

            return selectExpandNode;
        }
        private static void ValidateDepth(SelectExpandClause selectExpand, int maxDepth)
        {
            // do a DFS to see if there is any node that is too deep.
            Stack<Tuple<int, SelectExpandClause>> nodesToVisit = new Stack<Tuple<int, SelectExpandClause>>();
            nodesToVisit.Push(Tuple.Create(0, selectExpand));
            while (nodesToVisit.Count > 0)
            {
                Tuple<int, SelectExpandClause> tuple = nodesToVisit.Pop();
                int currentDepth = tuple.Item1;
                SelectExpandClause currentNode = tuple.Item2;

                ExpandedNavigationSelectItem[] expandItems = currentNode.SelectedItems.OfType<ExpandedNavigationSelectItem>().ToArray();
                if (expandItems.Length > 0 && currentDepth == maxDepth)
                {
                    throw new ODataException(
                        Error.Format(SRResources.MaxExpandDepthExceeded, maxDepth, "MaxExpansionDepth"));
                }

                foreach (ExpandedNavigationSelectItem expandItem in expandItems)
                {
                    nodesToVisit.Push(Tuple.Create(currentDepth + 1, expandItem.SelectAndExpand));
                }
            }
        }
        public void ProcessLevelsCorrectly_WithNestedLevels()
        {
            // Arrange
            var model   = ODataLevelsTest.GetEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("Microsoft.AspNet.OData.Test.Routing.LevelsEntity"));

            context.RequestContainer = new MockContainer();
            var selectExpand = new SelectExpandQueryOption(
                select: null,
                expand: "Parent($expand=DerivedAncestors($levels=2);$levels=max)",
                context: context);

            selectExpand.LevelsMaxLiteralExpansionDepth = 4;

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            Assert.True(clause.AllSelected);
            Assert.Single(clause.SelectedItems);

            // Level 1 of Parent.
            var parent = Assert.IsType <ExpandedNavigationSelectItem>(clause.SelectedItems.Single());

            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)parent.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(parent.LevelsOption);

            var clauseOfParent = parent.SelectAndExpand;

            Assert.True(clauseOfParent.AllSelected);
            Assert.Equal(2, clauseOfParent.SelectedItems.Count());

            // Level 1 of DerivedAncestors.
            var derivedAncestors = Assert.Single(clauseOfParent.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                                     item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                                     ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "DerivedAncestors"));

            Assert.Null(derivedAncestors.LevelsOption);

            var clauseOfDerivedAncestors = derivedAncestors.SelectAndExpand;

            Assert.True(clauseOfDerivedAncestors.AllSelected);
            Assert.Single(clauseOfDerivedAncestors.SelectedItems);

            // Level 2 of DerivedAncestors.
            derivedAncestors = Assert.IsType <ExpandedNavigationSelectItem>(clauseOfDerivedAncestors.SelectedItems.Single());
            Assert.Equal(
                "DerivedAncestors",
                ((NavigationPropertySegment)derivedAncestors.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(derivedAncestors.LevelsOption);

            clauseOfDerivedAncestors = derivedAncestors.SelectAndExpand;
            Assert.True(clauseOfDerivedAncestors.AllSelected);
            Assert.Empty(clauseOfDerivedAncestors.SelectedItems);

            // Level 2 of Parent.
            parent = Assert.Single(clauseOfParent.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                       item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                       ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "Parent"));
            Assert.Null(parent.LevelsOption);

            clauseOfParent = parent.SelectAndExpand;
            Assert.True(clauseOfParent.AllSelected);
            Assert.Single(clauseOfParent.SelectedItems);

            // Level 1 of DerivedAncestors.
            derivedAncestors = Assert.Single(clauseOfParent.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                                 item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                                 ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "DerivedAncestors"));
            Assert.Null(derivedAncestors.LevelsOption);

            clauseOfDerivedAncestors = derivedAncestors.SelectAndExpand;
            Assert.True(clauseOfDerivedAncestors.AllSelected);
            Assert.Single(clauseOfDerivedAncestors.SelectedItems);

            // Level 2 of DerivedAncestors.
            derivedAncestors = Assert.IsType <ExpandedNavigationSelectItem>(clauseOfDerivedAncestors.SelectedItems.Single());
            Assert.Equal(
                "DerivedAncestors",
                ((NavigationPropertySegment)derivedAncestors.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(derivedAncestors.LevelsOption);

            clauseOfDerivedAncestors = derivedAncestors.SelectAndExpand;
            Assert.True(clauseOfDerivedAncestors.AllSelected);
            Assert.Empty(clauseOfDerivedAncestors.SelectedItems);
        }
예제 #9
0
        private void GetAutoSelectExpandItems(IEdmEntityType baseEntityType, IEdmModel model, IEdmNavigationSource navigationSource, bool isAllSelected,
                                              ModelBoundQuerySettings modelBoundQuerySettings, int depth, out List <SelectItem> autoSelectItems, out List <SelectItem> autoExpandItems)
        {
            autoSelectItems = new List <SelectItem>();
            autoExpandItems = new List <SelectItem>();

            if (baseEntityType == null)
            {
                return;
            }

            IList <SelectModelPath> autoSelectProperties = model.GetAutoSelectPaths(baseEntityType, null, modelBoundQuerySettings);

            foreach (var autoSelectProperty in autoSelectProperties)
            {
                ODataSelectPath odataSelectPath = BuildSelectPath(autoSelectProperty, navigationSource);
                PathSelectItem  pathSelectItem  = new PathSelectItem(odataSelectPath);
                autoSelectItems.Add(pathSelectItem);
            }

            depth--;
            if (depth < 0)
            {
                return;
            }

            IList <ExpandModelPath> autoExpandNavigationProperties = model.GetAutoExpandPaths(baseEntityType, null, !isAllSelected, modelBoundQuerySettings);

            foreach (ExpandModelPath itemPath in autoExpandNavigationProperties)
            {
                string navigationPath = itemPath.NavigationPropertyPath;
                IEdmNavigationProperty navigationProperty = itemPath.Navigation;

                IEdmNavigationSource currentEdmNavigationSource;
                if (navigationPath != null)
                {
                    currentEdmNavigationSource = navigationSource.FindNavigationTarget(navigationProperty);
                }
                else
                {
                    currentEdmNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, new EdmPathExpression(navigationPath));
                }

                if (currentEdmNavigationSource != null)
                {
                    ODataExpandPath expandPath = BuildExpandPath(itemPath, navigationSource, currentEdmNavigationSource);

                    SelectExpandClause           selectExpandClause = new SelectExpandClause(new List <SelectItem>(), true);
                    ExpandedNavigationSelectItem item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause);
                    modelBoundQuerySettings = model.GetModelBoundQuerySettings(navigationProperty, navigationProperty.ToEntityType());
                    List <SelectItem> nestedSelectItems;
                    List <SelectItem> nestedExpandItems;

                    int maxExpandDepth = GetMaxExpandDepth(modelBoundQuerySettings, navigationProperty.Name);
                    if (maxExpandDepth != 0 && maxExpandDepth < depth)
                    {
                        depth = maxExpandDepth;
                    }

                    GetAutoSelectExpandItems(
                        currentEdmNavigationSource.EntityType(),
                        model,
                        item.NavigationSource,
                        true,
                        modelBoundQuerySettings,
                        depth,
                        out nestedSelectItems,
                        out nestedExpandItems);

                    selectExpandClause = new SelectExpandClause(nestedSelectItems.Concat(nestedExpandItems), nestedSelectItems.Count == 0);
                    item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause);

                    autoExpandItems.Add(item);
                    if (!isAllSelected || autoSelectProperties.Any())
                    {
                        PathSelectItem pathSelectItem = new PathSelectItem(new ODataSelectPath(expandPath));
                        autoExpandItems.Add(pathSelectItem);
                    }
                }
            }
        }
예제 #10
0
        /// <summary>
        /// Creates a new instance of the <see cref="SelectExpandNode"/> class describing the set of structural properties,
        /// nested properties, navigation properties, and actions to select and expand for the given <paramref name="selectExpandClause"/>.
        /// </summary>
        /// <param name="selectExpandClause">The parsed $select and $expand query options.</param>
        /// <param name="structuredType">The structural type of the resource that would be written.</param>
        /// <param name="model">The <see cref="IEdmModel"/> that contains the given structural type.</param>
        public SelectExpandNode(SelectExpandClause selectExpandClause, IEdmStructuredType structuredType, IEdmModel model)
            : this()
        {
            if (structuredType == null)
            {
                throw Error.ArgumentNull("structuredType");
            }

            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            // So far, it includes all properties of primitive, enum and collection of them
            HashSet<IEdmStructuralProperty> allStructuralProperties = new HashSet<IEdmStructuralProperty>();

            // So far, it includes all properties of complex and collection of complex
            HashSet<IEdmStructuralProperty> allComplexStructuralProperties = new HashSet<IEdmStructuralProperty>();
            GetStructuralProperties(structuredType, allStructuralProperties, allComplexStructuralProperties);

            // So far, it includes all navigation properties
            HashSet<IEdmNavigationProperty> allNavigationProperties;
            HashSet<IEdmAction> allActions;
            HashSet<IEdmFunction> allFunctions;

            IEdmEntityType entityType = structuredType as IEdmEntityType;
            if (entityType != null)
            {
                allNavigationProperties = new HashSet<IEdmNavigationProperty>(entityType.NavigationProperties());
                allActions = new HashSet<IEdmAction>(model.GetAvailableActions(entityType));
                allFunctions = new HashSet<IEdmFunction>(model.GetAvailableFunctions(entityType));
            }
            else
            {
                allNavigationProperties = new HashSet<IEdmNavigationProperty>();
                allActions = new HashSet<IEdmAction>();
                allFunctions = new HashSet<IEdmFunction>();
            }

            if (selectExpandClause == null)
            {
                SelectedStructuralProperties = allStructuralProperties;
                SelectedComplexProperties = allComplexStructuralProperties;
                SelectedNavigationProperties = allNavigationProperties;
                SelectedActions = allActions;
                SelectedFunctions = allFunctions;
                SelectAllDynamicProperties = true;
            }
            else
            {
                if (selectExpandClause.AllSelected)
                {
                    SelectedStructuralProperties = allStructuralProperties;
                    SelectedComplexProperties = allComplexStructuralProperties;
                    SelectedNavigationProperties = allNavigationProperties;
                    SelectedActions = allActions;
                    SelectedFunctions = allFunctions;
                    SelectAllDynamicProperties = true;
                }
                else
                {
                    // Explicitly set SelectAllDynamicProperties as false, while the BuildSelections method will set it as true
                    // if it meets the select all condition.
                    SelectAllDynamicProperties = false;
                    BuildSelections(selectExpandClause, allStructuralProperties, allComplexStructuralProperties, allNavigationProperties, allActions, allFunctions);
                }

                BuildExpansions(selectExpandClause, allNavigationProperties);

                // remove expanded navigation properties from the selected navigation properties.
                SelectedNavigationProperties.ExceptWith(ExpandedProperties.Keys);
            }
        }
 private void BuildExpansions(SelectExpandClause selectExpandClause, HashSet<IEdmNavigationProperty> allNavigationProperties)
 {
     foreach (SelectItem selectItem in selectExpandClause.SelectedItems)
     {
         ExpandedNavigationSelectItem expandItem = selectItem as ExpandedNavigationSelectItem;
         if (expandItem != null)
         {
             ValidatePathIsSupported(expandItem.PathToNavigationProperty);
             NavigationPropertySegment navigationSegment = (NavigationPropertySegment)expandItem.PathToNavigationProperty.LastSegment;
             IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty;
             if (allNavigationProperties.Contains(navigationProperty))
             {
                 ExpandedNavigationProperties.Add(navigationProperty, expandItem.SelectAndExpand);
             }
         }
     }
 }
예제 #12
0
        // Generates the expression
        //      source => new Wrapper { Instance = source, Container = new PropertyContainer { ..expanded properties.. } }
        private Expression ProjectElement(Expression source, SelectExpandClause selectExpandClause, IEdmEntityType entityType, IEdmNavigationSource navigationSource)
        {
            Contract.Assert(source != null);

            Type elementType = source.Type;
            Type wrapperType = typeof(SelectExpandWrapper <>).MakeGenericType(elementType);
            List <MemberAssignment> wrapperTypeMemberAssignments = new List <MemberAssignment>();

            PropertyInfo wrapperProperty;
            bool         isInstancePropertySet  = false;
            bool         isTypeNamePropertySet  = false;
            bool         isContainerPropertySet = false;

            // Initialize property 'ModelID' on the wrapper class.
            // source = new Wrapper { ModelID = 'some-guid-id' }
            wrapperProperty = wrapperType.GetProperty("ModelID");
            wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, Expression.Constant(_modelID)));

            if (IsSelectAll(selectExpandClause))
            {
                // Initialize property 'Instance' on the wrapper class
                // source => new Wrapper { Instance = element }
                wrapperProperty = wrapperType.GetProperty("Instance");
                Contract.Assert(wrapperProperty != null);
                wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, source));
                isInstancePropertySet = true;
            }
            else
            {
                // Initialize property 'TypeName' on the wrapper class as we don't have the instance.
                Expression typeName = CreateTypeNameExpression(source, entityType, _model);
                if (typeName != null)
                {
                    wrapperProperty = wrapperType.GetProperty("TypeName");
                    Contract.Assert(wrapperProperty != null);
                    wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, typeName));
                    isTypeNamePropertySet = true;
                }
            }

            // Initialize the property 'Container' on the wrapper class
            // source => new Wrapper { Container =  new PropertyContainer { .... } }
            if (selectExpandClause != null)
            {
                Dictionary <IEdmNavigationProperty, ExpandedNavigationSelectItem> propertiesToExpand = GetPropertiesToExpandInQuery(selectExpandClause);
                ISet <IEdmStructuralProperty> autoSelectedProperties;

                ISet <IEdmStructuralProperty> propertiesToInclude = GetPropertiesToIncludeInQuery(selectExpandClause, entityType, navigationSource, _model, out autoSelectedProperties);
                bool isSelectingOpenTypeSegments = GetSelectsOpenTypeSegments(selectExpandClause, entityType);

                if (propertiesToExpand.Count > 0 || propertiesToInclude.Count > 0 || autoSelectedProperties.Count > 0)
                {
                    wrapperProperty = wrapperType.GetProperty("Container");
                    Contract.Assert(wrapperProperty != null);

                    Expression propertyContainerCreation =
                        BuildPropertyContainer(entityType, source, propertiesToExpand, propertiesToInclude, autoSelectedProperties, isSelectingOpenTypeSegments);

                    wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, propertyContainerCreation));
                    isContainerPropertySet = true;
                }
            }

            Type wrapperGenericType = GetWrapperGenericType(isInstancePropertySet, isTypeNamePropertySet, isContainerPropertySet);

            wrapperType = wrapperGenericType.MakeGenericType(elementType);
            return(Expression.MemberInit(Expression.New(wrapperType), wrapperTypeMemberAssignments));
        }
예제 #13
0
        public void SelectProperties_OnSubPropertyWithTypeCastFromComplex_SelectsExpectedProperties()
        {
            // Arrange
            EdmComplexType subComplexType = new EdmComplexType("NS", "CnAddress", _model.Address);

            subComplexType.AddStructuralProperty("SubAddressProperty", EdmPrimitiveTypeKind.String);
            subComplexType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo
            {
                Name = "CnAddressOrderNav",
                TargetMultiplicity = EdmMultiplicity.One,
                Target             = _model.Order
            });
            _model.Model.AddElement(subComplexType);

            string select = "Address/NS.CnAddress/SubAddressProperty";
            string expand = "Address/NS.CnAddress/CnAddressOrderNav";

            SelectExpandClause selectExpandClause = ParseSelectExpand(select, expand);

            // Act
            SelectExpandNode selectExpandNode = new SelectExpandNode(selectExpandClause, _model.Customer, _model.Model);

            // Assert: Top Level
            Assert.Null(selectExpandNode.SelectedStructuralProperties);
            Assert.Null(selectExpandNode.SelectedNavigationProperties);
            Assert.Null(selectExpandNode.ExpandedProperties); // Not expanded at first level

            Assert.NotNull(selectExpandNode.SelectedComplexTypeProperties);
            var firstLevelSelected = Assert.Single(selectExpandNode.SelectedComplexTypeProperties);

            Assert.Equal("Address", firstLevelSelected.Key.Name);

            Assert.NotNull(firstLevelSelected.Value);
            Assert.NotNull(firstLevelSelected.Value.SelectAndExpand);

            // Assert: Second Level
            {
                // use the base type to test
                SelectExpandNode subSelectExpandNode = new SelectExpandNode(firstLevelSelected.Value.SelectAndExpand, _model.Address, _model.Model);
                Assert.Null(subSelectExpandNode.SelectedStructuralProperties);
                Assert.Null(subSelectExpandNode.SelectedComplexTypeProperties);
                Assert.Null(subSelectExpandNode.ExpandedProperties);
                Assert.Null(subSelectExpandNode.SelectedNavigationProperties);
            }
            {
                // use the sub type to test
                SelectExpandNode subSelectExpandNode = new SelectExpandNode(firstLevelSelected.Value.SelectAndExpand, subComplexType, _model.Model);
                Assert.Null(subSelectExpandNode.SelectedComplexTypeProperties);
                Assert.NotNull(subSelectExpandNode.SelectedStructuralProperties);
                Assert.Equal("SubAddressProperty", Assert.Single(subSelectExpandNode.SelectedStructuralProperties).Name);

                Assert.NotNull(subSelectExpandNode.ExpandedProperties);
                var expandedProperty = Assert.Single(subSelectExpandNode.ExpandedProperties);
                Assert.Equal("CnAddressOrderNav", expandedProperty.Key.Name);

                Assert.NotNull(expandedProperty.Value);
                Assert.NotNull(expandedProperty.Value.SelectAndExpand);
                Assert.True(expandedProperty.Value.SelectAndExpand.AllSelected);
                Assert.Empty(expandedProperty.Value.SelectAndExpand.SelectedItems);
            }
        }
예제 #14
0
 public static void SnapResults(List <DeltaSnapshotEntry> results, IEnumerable entries, IEdmNavigationSource entitySource, SelectExpandClause selectExpandClause, string parentId, string relationShip)
 {
     foreach (object entry in entries)
     {
         SnapResult(results, entry, entitySource, selectExpandClause, parentId, relationShip);
     }
 }
        public void CreateODataFeed_SetsNextPageLink_WhenWritingTruncatedCollection_ForExpandedProperties()
        {
            // Arrange
            CustomersModelWithInheritance model = new CustomersModelWithInheritance();
            IEdmCollectionTypeReference customersType = new EdmCollectionTypeReference(new EdmCollectionType(model.Customer.AsReference()), isNullable: false);
            ODataFeedSerializer serializer = new ODataFeedSerializer(new DefaultODataSerializerProvider());
            SelectExpandClause selectExpandClause = new SelectExpandClause(new SelectItem[0], allSelected: true);
            IEdmNavigationProperty ordersProperty = model.Customer.NavigationProperties().First();
            EntityInstanceContext entity = new EntityInstanceContext
            {
                SerializerContext = new ODataSerializerContext { EntitySet = model.Customers, Model = model.Model }
            };
            ODataSerializerContext nestedContext = new ODataSerializerContext(entity, selectExpandClause, ordersProperty);
            TruncatedCollection<Order> orders = new TruncatedCollection<Order>(new[] { new Order(), new Order() }, pageSize: 1);

            Mock<EntitySetLinkBuilderAnnotation> linkBuilder = new Mock<EntitySetLinkBuilderAnnotation>();
            linkBuilder.Setup(l => l.BuildNavigationLink(entity, ordersProperty, ODataMetadataLevel.Default)).Returns(new Uri("http://navigation-link/"));
            model.Model.SetEntitySetLinkBuilder(model.Customers, linkBuilder.Object);
            model.Model.SetEntitySetLinkBuilder(model.Orders, new EntitySetLinkBuilderAnnotation());

            // Act
            ODataFeed feed = serializer.CreateODataFeed(orders, _customersType, nestedContext);

            // Assert
            Assert.Equal("http://navigation-link/?$skip=1", feed.NextPageLink.AbsoluteUri);
        }
예제 #16
0
        // Process $levels in ExpandedNavigationSelectItem.
        private ExpandedNavigationSelectItem ProcessLevels(
            ExpandedNavigationSelectItem expandItem,
            int levelsMaxLiteralExpansionDepth,
            ModelBoundQuerySettings querySettings,
            out bool levelsEncounteredInExpand,
            out bool isMaxLevelInExpand)
        {
            int level;

            isMaxLevelInExpand = false;

            if (expandItem.LevelsOption == null)
            {
                levelsEncounteredInExpand = false;
                level = 1;
            }
            else
            {
                levelsEncounteredInExpand = true;
                if (expandItem.LevelsOption.IsMaxLevel)
                {
                    isMaxLevelInExpand = true;
                    level = levelsMaxLiteralExpansionDepth;
                }
                else
                {
                    level = (int)expandItem.LevelsOption.Level;
                }
            }

            // Do not expand when:
            // 1. $levels is equal to or less than 0.
            // 2. $levels value is greater than current MaxExpansionDepth
            if (level <= 0 || level > levelsMaxLiteralExpansionDepth)
            {
                return(null);
            }

            ExpandedNavigationSelectItem item = null;
            SelectExpandClause           currentSelectExpandClause = null;
            SelectExpandClause           selectExpandClause        = null;
            bool levelsEncounteredInInnerExpand = false;
            bool isMaxLevelInInnerExpand        = false;
            var  entityType = expandItem.NavigationSource.EntityType();
            IEdmNavigationProperty navigationProperty =
                (expandItem.PathToNavigationProperty.LastSegment as NavigationPropertySegment).NavigationProperty;
            ModelBoundQuerySettings nestQuerySettings = EdmLibHelpers.GetModelBoundQuerySettings(navigationProperty,
                                                                                                 navigationProperty.ToEntityType(),
                                                                                                 Context.Model);

            // Try different expansion depth until expandItem.SelectAndExpand is successfully expanded
            while (selectExpandClause == null && level > 0)
            {
                selectExpandClause = ProcessLevels(
                    expandItem.SelectAndExpand,
                    levelsMaxLiteralExpansionDepth - level,
                    nestQuerySettings,
                    out levelsEncounteredInInnerExpand,
                    out isMaxLevelInInnerExpand);
                level--;
            }

            if (selectExpandClause == null)
            {
                return(null);
            }

            // Correct level value
            level++;
            List <SelectItem> originAutoSelectItems;
            List <SelectItem> originAutoExpandItems;
            int maxDepth = GetMaxExpandDepth(querySettings, navigationProperty.Name);

            if (maxDepth == 0 || levelsMaxLiteralExpansionDepth > maxDepth)
            {
                maxDepth = levelsMaxLiteralExpansionDepth;
            }

            GetAutoSelectExpandItems(
                entityType,
                Context.Model,
                expandItem.NavigationSource,
                selectExpandClause.AllSelected,
                nestQuerySettings,
                maxDepth - 1,
                out originAutoSelectItems,
                out originAutoExpandItems);
            if (expandItem.SelectAndExpand.SelectedItems.Any(it => it is PathSelectItem))
            {
                originAutoSelectItems.Clear();
            }

            if (level > 1)
            {
                RemoveSameExpandItem(navigationProperty, originAutoExpandItems);
            }

            List <SelectItem> autoExpandItems = new List <SelectItem>(originAutoExpandItems);
            bool hasAutoSelectExpandInExpand  = (originAutoSelectItems.Count() + originAutoExpandItems.Count() != 0);
            bool allSelected       = originAutoSelectItems.Count == 0 && selectExpandClause.AllSelected;
            var  typeLevelSettings = EdmLibHelpers.GetModelBoundQuerySettings(entityType, this.Context.Model, this.Context.DefaultQuerySettings);
            bool allAutoSelected   = (typeLevelSettings != null && typeLevelSettings.DefaultSelectType == SelectExpandType.Automatic);

            while (level > 0)
            {
                autoExpandItems = RemoveExpandItemExceedMaxDepth(maxDepth - level, originAutoExpandItems);
                if (item == null)
                {
                    if (hasAutoSelectExpandInExpand)
                    {
                        currentSelectExpandClause = new SelectExpandClause(
                            new SelectItem[] { }.Concat(selectExpandClause.SelectedItems)
                            .Concat(originAutoSelectItems).Concat(autoExpandItems),
                            allSelected,
                            allAutoSelected);
                    }
                    else
                    {
                        currentSelectExpandClause = selectExpandClause;
                    }
                }
                else if (selectExpandClause.AllSelected)
                {
                    // Concat the processed items
                    currentSelectExpandClause = new SelectExpandClause(
                        new SelectItem[] { item }.Concat(selectExpandClause.SelectedItems)
                        .Concat(originAutoSelectItems).Concat(autoExpandItems),
                        allSelected,
                        allAutoSelected);
                }
                else
                {
                    // PathSelectItem is needed for the expanded item if AllSelected is false.
                    PathSelectItem pathSelectItem = new PathSelectItem(
                        new ODataSelectPath(expandItem.PathToNavigationProperty));

                    // Keep default SelectItems before expanded item to keep consistent with normal SelectExpandClause
                    SelectItem[] items = new SelectItem[] { item, pathSelectItem };
                    currentSelectExpandClause = new SelectExpandClause(
                        new SelectItem[] { }.Concat(selectExpandClause.SelectedItems)
                        .Concat(items)
                        .Concat(originAutoSelectItems).Concat(autoExpandItems),
                        allSelected,
                        allAutoSelected);
                }

                // Construct a new ExpandedNavigationSelectItem with current SelectExpandClause.
                item = new ExpandedNavigationSelectItem(
                    expandItem.PathToNavigationProperty,
                    expandItem.NavigationSource,
                    currentSelectExpandClause,
                    expandItem.FilterOption,
                    expandItem.OrderByOption,
                    expandItem.TopOption,
                    expandItem.SkipOption,
                    expandItem.CountOption,
                    expandItem.SearchOption,
                    null,
                    expandItem.ComputeOption,
                    expandItem.ApplyOption);

                level--;

                // Need expand and construct selectExpandClause every time if it is max level in inner expand
                if (isMaxLevelInInnerExpand)
                {
                    selectExpandClause = ProcessLevels(
                        expandItem.SelectAndExpand,
                        levelsMaxLiteralExpansionDepth - level,
                        nestQuerySettings,
                        out levelsEncounteredInInnerExpand,
                        out isMaxLevelInInnerExpand);
                }
            }

            levelsEncounteredInExpand = levelsEncounteredInExpand || levelsEncounteredInInnerExpand || hasAutoSelectExpandInExpand;
            isMaxLevelInExpand        = isMaxLevelInExpand || isMaxLevelInInnerExpand;

            return(item);
        }
        private void BuildSelections(SelectExpandClause selectExpandClause, HashSet<IEdmStructuralProperty> allStructuralProperties, HashSet<IEdmNavigationProperty> allNavigationProperties, HashSet<IEdmFunctionImport> allActions)
        {
            foreach (SelectItem selectItem in selectExpandClause.SelectedItems)
            {
                if (selectItem is ExpandedNavigationSelectItem)
                {
                    continue;
                }

                PathSelectItem pathSelectItem = selectItem as PathSelectItem;

                if (pathSelectItem != null)
                {
                    ValidatePathIsSupported(pathSelectItem.SelectedPath);
                    ODataPathSegment segment = pathSelectItem.SelectedPath.LastSegment;

                    NavigationPropertySegment navigationPropertySegment = segment as NavigationPropertySegment;
                    if (navigationPropertySegment != null)
                    {
                        IEdmNavigationProperty navigationProperty = navigationPropertySegment.NavigationProperty;
                        if (allNavigationProperties.Contains(navigationProperty))
                        {
                            SelectedNavigationProperties.Add(navigationProperty);
                        }
                        continue;
                    }

                    PropertySegment structuralPropertySegment = segment as PropertySegment;
                    if (structuralPropertySegment != null)
                    {
                        IEdmStructuralProperty structuralProperty = structuralPropertySegment.Property;
                        if (allStructuralProperties.Contains(structuralProperty))
                        {
                            SelectedStructuralProperties.Add(structuralProperty);
                        }
                        continue;
                    }

                    OperationSegment operationSegment = segment as OperationSegment;
                    if (operationSegment != null)
                    {
                        foreach (IEdmFunctionImport action in operationSegment.Operations)
                        {
                            if (allActions.Contains(action))
                            {
                                SelectedActions.Add(action);
                            }
                        }
                        continue;
                    }

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

                WildcardSelectItem wildCardSelectItem = selectItem as WildcardSelectItem;
                if (wildCardSelectItem != null)
                {
                    SelectedStructuralProperties = allStructuralProperties;
                    SelectedNavigationProperties = allNavigationProperties;
                    continue;
                }

                ContainerQualifiedWildcardSelectItem wildCardActionSelection = selectItem as ContainerQualifiedWildcardSelectItem;
                if (wildCardActionSelection != null)
                {
                    IEnumerable<IEdmFunctionImport> actionsInThisContainer = allActions.Where(a => a.Container == wildCardActionSelection.Container);
                    foreach (IEdmFunctionImport action in actionsInThisContainer)
                    {
                        SelectedActions.Add(action);
                    }
                    continue;
                }

                throw new ODataException(Error.Format(SRResources.SelectionTypeNotSupported, selectItem.GetType().Name));
            }
        }
        public void ProjectAsWrapper_ProjectionContainsExpandedProperties()
        {
            // Arrange
            Order order = new Order();
            ExpandItem expandItem = new ExpandItem(new ODataPath(new NavigationPropertySegment(_model.Order.NavigationProperties().Single())), _model.Customers);
            Expansion expansion = new Expansion(new[] { expandItem });
            SelectExpandClause selectExpand = new SelectExpandClause(selection: null, expansion: expansion);
            Expression source = Expression.Constant(order);

            // Act
            Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order);

            // Assert
            SelectExpandWrapper<Order> projectedOrder = Expression.Lambda(projection).Compile().DynamicInvoke() as SelectExpandWrapper<Order>;
            Assert.NotNull(projectedOrder);
            Assert.Contains("Customer", projectedOrder.Container.ToDictionary().Keys);
        }
예제 #19
0
 /// <summary>
 /// Build a property visitor to visit the select tree and decorate a SelectExpandClause
 /// </summary>
 /// <param name="model">The model used for binding.</param>
 /// <param name="edmType">The entity type that the $select is being applied to.</param>
 /// <param name="maxDepth">the maximum recursive depth.</param>
 /// <param name="expandClauseToDecorate">The already built expand clause to decorate</param>
 /// <param name="resolver">Resolver for uri parser.</param>
 public SelectPropertyVisitor(IEdmModel model, IEdmStructuredType edmType, int maxDepth, SelectExpandClause expandClauseToDecorate, ODataUriResolver resolver)
 {
     this.model    = model;
     this.edmType  = edmType;
     this.maxDepth = maxDepth;
     this.expandClauseToDecorate = expandClauseToDecorate;
     this.resolver = resolver ?? ODataUriResolver.Default;
 }
예제 #20
0
        // Generates the expression
        //      source => new Wrapper { Instance = source, Container = new PropertyContainer { ..expanded properties.. } }
        private Expression ProjectElement(Expression source, SelectExpandClause selectExpandClause, IEdmEntityType entityType)
        {
            Contract.Assert(source != null);

            Type wrapperType = typeof(SelectExpandWrapper<>).MakeGenericType(source.Type);
            List<MemberAssignment> wrapperTypeMemberAssignments = new List<MemberAssignment>();

            PropertyInfo wrapperProperty;

            // Initialize property 'ModelID' on the wrapper class.
            // source = new Wrapper { ModelID = 'some-guid-id' }
            wrapperProperty = wrapperType.GetProperty("ModelID");
            wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, Expression.Constant(_modelID)));

            if (IsSelectAll(selectExpandClause))
            {
                // Initialize property 'Instance' on the wrapper class
                // source => new Wrapper { Instance = element }
                wrapperProperty = wrapperType.GetProperty("Instance");
                Contract.Assert(wrapperProperty != null);
                wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, source));
            }
            else
            {
                // Initialize property 'TypeName' on the wrapper class as we don't have the instance.
                Expression typeName = CreateTypeNameExpression(source, entityType, _model);
                if (typeName != null)
                {
                    wrapperProperty = wrapperType.GetProperty("TypeName");
                    Contract.Assert(wrapperProperty != null);
                    wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, typeName));
                }
            }

            // Initialize the property 'Container' on the wrapper class
            // source => new Wrapper { Container =  new PropertyContainer { .... } }
            if (selectExpandClause != null)
            {
                Dictionary<IEdmNavigationProperty, SelectExpandClause> propertiesToExpand = GetPropertiesToExpandInQuery(selectExpandClause);
                ISet<IEdmStructuralProperty> autoSelectedProperties;
                ISet<IEdmStructuralProperty> propertiesToInclude = GetPropertiesToIncludeInQuery(selectExpandClause, entityType, out autoSelectedProperties);

                if (propertiesToExpand.Count > 0 || propertiesToInclude.Count > 0)
                {
                    wrapperProperty = wrapperType.GetProperty("Container");
                    Contract.Assert(wrapperProperty != null);

                    Expression propertyContainerCreation =
                        BuildPropertyContainer(entityType, source, propertiesToExpand, propertiesToInclude, autoSelectedProperties);

                    wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, propertyContainerCreation));
                }
            }

            return Expression.MemberInit(Expression.New(wrapperType), wrapperTypeMemberAssignments);
        }
        /// <summary>
        /// Create a ExpandTransformationNode.
        /// </summary>
        /// <param name="expandClause">A <see cref="SelectExpandClause"/> representing the metadata bound expand expression.</param>
        public ExpandTransformationNode(SelectExpandClause expandClause)
        {
            ExceptionUtils.CheckArgumentNotNull(expandClause, "expandClause");

            this.expandClause = expandClause;
        }
예제 #22
0
        // new CollectionWrapper<ElementType> { Instance = source.Select((ElementType element) => new Wrapper { }) }
        private Expression ProjectCollection(Expression source, Type elementType, SelectExpandClause selectExpandClause, IEdmEntityType entityType)
        {
            ParameterExpression element = Expression.Parameter(elementType);

            // expression
            //      new Wrapper { }
            Expression projection = ProjectElement(element, selectExpandClause, entityType);

            // expression
            //      (ElementType element) => new Wrapper { }
            LambdaExpression selector = Expression.Lambda(projection, element);

            // expression
            //      source.Select((ElementType element) => new Wrapper { })
            Expression selectedExpresion = Expression.Call(GetSelectMethod(elementType), source, selector);

            if (_settings.HandleNullPropagation == HandleNullPropagationOption.True)
            {
                // source == null ? null : projectedCollection
                return Expression.Condition(
                        test: Expression.Equal(source, Expression.Constant(null)),
                        ifTrue: Expression.Constant(null, selectedExpresion.Type),
                        ifFalse: selectedExpresion);
            }
            else
            {
                return selectedExpresion;
            }
        }
예제 #23
0
 /// <summary>
 /// Decorate an expand tree using a select token.
 /// </summary>
 /// <param name="subExpand">the already built sub expand</param>
 /// <param name="currentNavProp">the current navigation property</param>
 /// <param name="select">the select token to use</param>
 /// <returns>A new SelectExpand clause decorated with the select token.</returns>
 protected abstract SelectExpandClause DecorateExpandWithSelect(SelectExpandClause subExpand, IEdmNavigationProperty currentNavProp, SelectToken select);
예제 #24
0
        private static Dictionary<IEdmNavigationProperty, SelectExpandClause> GetPropertiesToExpandInQuery(SelectExpandClause selectExpandClause)
        {
            Dictionary<IEdmNavigationProperty, SelectExpandClause> properties = new Dictionary<IEdmNavigationProperty, SelectExpandClause>();

            Expansion expansion = selectExpandClause.Expansion;
            if (expansion != null)
            {
                foreach (ExpandItem expandItem in expansion.ExpandItems)
                {
                    SelectExpandNode.ValidatePathIsSupported(expandItem.PathToNavigationProperty);
                    NavigationPropertySegment navigationSegment = expandItem.PathToNavigationProperty.LastSegment as NavigationPropertySegment;
                    if (navigationSegment == null)
                    {
                        throw new ODataException(SRResources.UnsupportedSelectExpandPath);
                    }

                    properties[navigationSegment.NavigationProperty] = expandItem.SelectExpandOption;
                }
            }

            return properties;
        }
예제 #25
0
        // new CollectionWrapper<ElementType> { Instance = source.Select((ElementType element) => new Wrapper { }) }
        private Expression ProjectCollection(Expression source, Type elementType, SelectExpandClause selectExpandClause, IEdmEntityType entityType, IEdmNavigationSource navigationSource, ExpandedNavigationSelectItem expandedItem)
        {
            ParameterExpression element = Expression.Parameter(elementType);

            // expression
            //      new Wrapper { }
            Expression projection = ProjectElement(element, selectExpandClause, entityType, navigationSource);

            // expression
            //      (ElementType element) => new Wrapper { }
            LambdaExpression selector = Expression.Lambda(projection, element);

            if (expandedItem != null)
            {
                source = AddOrderByQueryForSource(source, expandedItem.OrderByOption, elementType);
            }

            if (_settings.PageSize.HasValue ||
                (expandedItem != null && (expandedItem.TopOption.HasValue || expandedItem.SkipOption.HasValue)))
            {
                // nested paging. Need to apply order by first, and take one more than page size as we need to know
                // whether the collection was truncated or not while generating next page links.
                IEnumerable <IEdmStructuralProperty> properties =
                    entityType.Key().Any()
                        ? entityType.Key()
                        : entityType
                    .StructuralProperties()
                    .Where(property => property.Type.IsPrimitive()).OrderBy(property => property.Name);

                if (expandedItem == null || expandedItem.OrderByOption == null)
                {
                    bool alreadyOrdered = false;
                    foreach (var prop in properties)
                    {
                        source = ExpressionHelpers.OrderByPropertyExpression(source, prop.Name, elementType,
                                                                             alreadyOrdered);
                        if (!alreadyOrdered)
                        {
                            alreadyOrdered = true;
                        }
                    }
                }

                if (expandedItem != null && expandedItem.SkipOption.HasValue)
                {
                    Contract.Assert(expandedItem.SkipOption.Value <= Int32.MaxValue);
                    source = ExpressionHelpers.Skip(source, (int)expandedItem.SkipOption.Value, elementType,
                                                    _settings.EnableConstantParameterization);
                }

                if (expandedItem != null && expandedItem.TopOption.HasValue)
                {
                    Contract.Assert(expandedItem.TopOption.Value <= Int32.MaxValue);
                    source = ExpressionHelpers.Take(source, (int)expandedItem.TopOption.Value, elementType,
                                                    _settings.EnableConstantParameterization);
                }

                if (_settings.PageSize.HasValue)
                {
                    source = ExpressionHelpers.Take(source, _settings.PageSize.Value + 1, elementType,
                                                    _settings.EnableConstantParameterization);
                }
            }

            // expression
            //      source.Select((ElementType element) => new Wrapper { })
            Expression selectedExpresion = Expression.Call(GetSelectMethod(elementType, projection.Type), source, selector);

            if (_settings.HandleNullPropagation == HandleNullPropagationOption.True)
            {
                // source == null ? null : projectedCollection
                return(Expression.Condition(
                           test: Expression.Equal(source, Expression.Constant(null)),
                           ifTrue: Expression.Constant(null, selectedExpresion.Type),
                           ifFalse: selectedExpresion));
            }
            else
            {
                return(selectedExpresion);
            }
        }
예제 #26
0
        private static ISet<IEdmStructuralProperty> GetPropertiesToIncludeInQuery(
            SelectExpandClause selectExpandClause, IEdmEntityType entityType, out ISet<IEdmStructuralProperty> autoSelectedProperties)
        {
            autoSelectedProperties = new HashSet<IEdmStructuralProperty>();
            HashSet<IEdmStructuralProperty> propertiesToInclude = new HashSet<IEdmStructuralProperty>();

            PartialSelection selection = selectExpandClause.Selection as PartialSelection;
            if (selection != null && !selection.SelectedItems.OfType<WildcardSelectionItem>().Any())
            {
                // only select requested properties and keys.
                foreach (PathSelectionItem pathSelectionItem in selection.SelectedItems.OfType<PathSelectionItem>())
                {
                    SelectExpandNode.ValidatePathIsSupported(pathSelectionItem.SelectedPath);
                    PropertySegment structuralPropertySegment = pathSelectionItem.SelectedPath.LastSegment as PropertySegment;
                    if (structuralPropertySegment != null)
                    {
                        propertiesToInclude.Add(structuralPropertySegment.Property);
                    }
                }

                // add keys
                foreach (IEdmStructuralProperty keyProperty in entityType.Key())
                {
                    if (!propertiesToInclude.Contains(keyProperty))
                    {
                        autoSelectedProperties.Add(keyProperty);
                    }
                }
            }

            return propertiesToInclude;
        }
예제 #27
0
        /// <summary>
        /// Decorate an expand tree using a select token.
        /// </summary>
        /// <param name="subExpand">the already built sub expand</param>
        /// <param name="currentNavProp">the current navigation property</param>
        /// <param name="select">the select token to use</param>
        /// <returns>A new SelectExpand clause decorated with the select token.</returns>
        private SelectExpandClause DecorateExpandWithSelect(SelectExpandClause subExpand, IEdmNavigationProperty currentNavProp, SelectToken select)
        {
            SelectBinder selectBinder = new SelectBinder(this.Model, currentNavProp.ToEntityType(), this.Settings.SelectExpandLimit, subExpand, this.configuration.Resolver);

            return(selectBinder.Bind(select));
        }
예제 #28
0
        private static bool IsSelectAll(SelectExpandClause selectExpandCaluse)
        {
            if (selectExpandCaluse == null
                || selectExpandCaluse.Selection == null
                || selectExpandCaluse.Selection == AllSelection.Instance)
            {
                return true;
            }

            PartialSelection partialSelection = selectExpandCaluse.Selection as PartialSelection;
            if (partialSelection != null && partialSelection.SelectedItems.OfType<WildcardSelectionItem>().Any())
            {
                return true;
            }

            return false;
        }
예제 #29
0
        public void BuildSelectExpandNode_ThrowsODataException_IfUnknownSelectItemPresent()
        {
            SelectExpandClause selectExpandClause = new SelectExpandClause(new SelectItem[] { new Mock<SelectItem>().Object }, allSelected: false);
            IEdmEntityType entityType = _model.Customer;

            Assert.Throws<ODataException>(
                () => new SelectExpandNode(selectExpandClause, entityType, _model.Model),
                "$select does not support selections of type 'SelectItemProxy'.");
        }
예제 #30
0
 internal Expression ProjectAsWrapper(Expression source, SelectExpandClause selectExpandClause, IEdmEntityType entityType)
 {
     Type elementType;
     if (source.Type.IsCollection(out elementType))
     {
         // new CollectionWrapper<ElementType> { Instance = source.Select(s => new Wrapper { ... }) };
         return ProjectCollection(source, elementType, selectExpandClause, entityType);
     }
     else
     {
         // new Wrapper { v1 = source.property ... }
         return ProjectElement(source, selectExpandClause, entityType);
     }
 }
        public void ProcessLevelsCorrectly_WithMultipleProperties()
        {
            // Arrange
            var model   = ODataLevelsTest.GetEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("Microsoft.AspNet.OData.Test.Routing.LevelsEntity"));

            context.RequestContainer = new MockContainer();
            var selectExpand = new SelectExpandQueryOption(
                select: null,
                expand: "Parent($expand=Parent($levels=max),DerivedAncestors($levels=2;$select=ID)),BaseEntities($levels=2)",
                context: context);

            selectExpand.LevelsMaxLiteralExpansionDepth = 3;

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            Assert.True(clause.AllSelected);
            Assert.Equal(2, clause.SelectedItems.Count());

            // Top level Parent.
            var parent = Assert.Single(clause.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                           item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                           ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "Parent"));

            Assert.Null(parent.LevelsOption);

            var clauseOfParent = parent.SelectAndExpand;

            Assert.True(clauseOfParent.AllSelected);
            Assert.Equal(2, clauseOfParent.SelectedItems.Count());

            // Level 1 of inline Parent.
            var inlineParent = Assert.Single(clauseOfParent.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                                 item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                                 ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "Parent"));

            Assert.Null(inlineParent.LevelsOption);

            // Level 2 of inline Parent.
            var inlineParentClause = inlineParent.SelectAndExpand;

            Assert.True(inlineParentClause.AllSelected);
            Assert.Single(inlineParentClause.SelectedItems);

            inlineParent = Assert.IsType <ExpandedNavigationSelectItem>(inlineParentClause.SelectedItems.Single());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)inlineParent.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(inlineParent.LevelsOption);

            inlineParentClause = inlineParent.SelectAndExpand;
            Assert.True(inlineParentClause.AllSelected);
            Assert.Empty(inlineParentClause.SelectedItems);

            // Level 1 of inline DerivedAncestors.
            var inlineDerivedAncestors = Assert.Single(clauseOfParent.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                                           item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                                           ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "DerivedAncestors"));

            Assert.Null(inlineDerivedAncestors.LevelsOption);

            // Level 2 of inline DerivedAncestors.
            var inlineDerivedAncestorsClause = inlineDerivedAncestors.SelectAndExpand;

            Assert.False(inlineDerivedAncestorsClause.AllSelected);
            Assert.Equal(3, inlineDerivedAncestorsClause.SelectedItems.Count());

            var idItem = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType <PathSelectItem>().Where(
                                           item => item.SelectedPath.FirstSegment is PropertySegment));

            Assert.Equal("ID", ((PropertySegment)idItem.SelectedPath.FirstSegment).Property.Name);

            var derivedAncestorsItem = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType <PathSelectItem>().Where(
                                                         item => item.SelectedPath.FirstSegment is NavigationPropertySegment));

            Assert.Equal(
                "DerivedAncestors",
                ((NavigationPropertySegment)derivedAncestorsItem.SelectedPath.FirstSegment).NavigationProperty.Name);

            inlineDerivedAncestors = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType <ExpandedNavigationSelectItem>());
            Assert.Equal(
                "DerivedAncestors",
                ((NavigationPropertySegment)inlineDerivedAncestors.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(inlineDerivedAncestors.LevelsOption);

            inlineDerivedAncestorsClause = inlineDerivedAncestors.SelectAndExpand;
            Assert.False(inlineDerivedAncestorsClause.AllSelected);
            Assert.Single(inlineDerivedAncestorsClause.SelectedItems);

            idItem = Assert.Single(inlineDerivedAncestorsClause.SelectedItems.OfType <PathSelectItem>());
            Assert.Equal("ID", ((PropertySegment)idItem.SelectedPath.FirstSegment).Property.Name);

            // Level 1 of BaseEntities.
            var baseEntities = Assert.Single(clause.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                                                 item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                                                 ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty.Name == "BaseEntities"));

            Assert.Null(baseEntities.LevelsOption);

            // Level 2 of BaseEntities.
            var baseEntitiesClause = baseEntities.SelectAndExpand;

            Assert.True(baseEntitiesClause.AllSelected);
            Assert.Single(baseEntitiesClause.SelectedItems);

            baseEntities = Assert.IsType <ExpandedNavigationSelectItem>(baseEntitiesClause.SelectedItems.Single());
            Assert.Equal(
                "BaseEntities",
                ((NavigationPropertySegment)baseEntities.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(baseEntities.LevelsOption);

            baseEntitiesClause = baseEntities.SelectAndExpand;
            Assert.True(baseEntitiesClause.AllSelected);
            Assert.Empty(baseEntitiesClause.SelectedItems);
        }
예제 #32
0
        public void BuildSelectExpandNode_ThrowsODataException_IfUnknownSelectionItemPresent()
        {
            Selection selection = new PartialSelection(new[] { new Mock<SelectionItem>().Object });
            SelectExpandClause selectExpandClause = new SelectExpandClause(selection, _emptyExpansion);
            IEdmEntityTypeReference entityType = new EdmEntityTypeReference(_model.Customer, false);

            Assert.Throws<ODataException>(
                () => SelectExpandNode.BuildSelectExpandNode(selectExpandClause, entityType, _model.Model),
                "$select does not support selections of type 'SelectionItemProxy'.");
        }
        public void ProcessLevelsCorrectly_WithAutoExpand(string url)
        {
            // Arrange
            var model   = GetAutoExpandEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("Microsoft.AspNet.OData.Test.Common.Models.AutoExpandCustomer"));
            var request     = RequestFactory.Create(HttpMethod.Get, url);
            var queryOption = new ODataQueryOptions(context, request);

            queryOption.AddAutoSelectExpandProperties();
            var selectExpand = queryOption.SelectExpand;

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            Assert.True(clause.AllSelected);
            Assert.Equal(2, clause.SelectedItems.Count());

            // Level 1 of Customer.
            var cutomer = Assert.Single(
                clause.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                    item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                    ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty
                    .Name == "Friend")
                );

            var clauseOfCustomer = cutomer.SelectAndExpand;

            Assert.True(clauseOfCustomer.AllSelected);
            Assert.Equal(2, clauseOfCustomer.SelectedItems.Count());

            // Order under Customer.
            var order = Assert.Single(
                clause.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                    item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                    ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty
                    .Name == "Order")
                );

            Assert.Null(order.LevelsOption);

            var clauseOfOrder = order.SelectAndExpand;

            Assert.True(clauseOfOrder.AllSelected);
            Assert.Single(clauseOfOrder.SelectedItems);

            // Choice Order under Order
            var choiceOrder = Assert.IsType <ExpandedNavigationSelectItem>(clauseOfOrder.SelectedItems.Single());

            Assert.Null(choiceOrder.LevelsOption);
            Assert.True(choiceOrder.SelectAndExpand.AllSelected);
            Assert.Empty(choiceOrder.SelectAndExpand.SelectedItems);

            // Level 2 of Order.
            order = Assert.Single(
                clauseOfCustomer.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                    item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                    ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty
                    .Name == "Order")
                );
            Assert.Null(order.LevelsOption);

            clauseOfOrder = order.SelectAndExpand;
            Assert.True(clauseOfOrder.AllSelected);
            Assert.Empty(clauseOfOrder.SelectedItems);

            // Level 2 of Customer.
            cutomer = Assert.Single(
                clauseOfCustomer.SelectedItems.OfType <ExpandedNavigationSelectItem>().Where(
                    item => item.PathToNavigationProperty.FirstSegment is NavigationPropertySegment &&
                    ((NavigationPropertySegment)item.PathToNavigationProperty.FirstSegment).NavigationProperty
                    .Name == "Friend")
                );
            Assert.Null(cutomer.LevelsOption);

            clauseOfCustomer = cutomer.SelectAndExpand;
            Assert.True(clauseOfCustomer.AllSelected);
            Assert.Empty(clauseOfCustomer.SelectedItems);
        }
        public void ProjectAsWrapper_NonCollection_ProjectedValueNullAndHandleNullPropagationTrue()
        {
            // Arrange
            _settings.HandleNullPropagation = HandleNullPropagationOption.True;
            ExpandedNavigationSelectItem expandItem = new ExpandedNavigationSelectItem(
                new ODataExpandPath(new NavigationPropertySegment(_model.Order.NavigationProperties().Single(), entitySet: _model.Customers)),
                _model.Customers,
                selectExpandOption: null);
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[] { expandItem }, allSelected: true);
            Expression source = Expression.Constant(null, typeof(Order));

            // Act
            Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order);

            // Assert
            SelectExpandWrapper<Order> projectedOrder = Expression.Lambda(projection).Compile().DynamicInvoke() as SelectExpandWrapper<Order>;
            Assert.NotNull(projectedOrder);
            Assert.Null(projectedOrder.Instance);
            Assert.Null(projectedOrder.Container.ToDictionary()["Customer"]);
        }
예제 #35
0
        private void GetAutoSelectExpandItems(
            IEdmEntityType baseEntityType,
            IEdmModel model,
            IEdmNavigationSource navigationSource,
            bool isAllSelected,
            ModelBoundQuerySettings modelBoundQuerySettings,
            int depth,
            out List <SelectItem> autoSelectItems,
            out List <SelectItem> autoExpandItems)
        {
            autoSelectItems = new List <SelectItem>();
            var autoSelectProperties = EdmLibHelpers.GetAutoSelectProperties(null,
                                                                             baseEntityType, model, modelBoundQuerySettings);

            foreach (var autoSelectProperty in autoSelectProperties)
            {
                List <ODataPathSegment> pathSegments = new List <ODataPathSegment>()
                {
                    new PropertySegment(autoSelectProperty)
                };

                PathSelectItem pathSelectItem = new PathSelectItem(
                    new ODataSelectPath(pathSegments));
                autoSelectItems.Add(pathSelectItem);
            }

            autoExpandItems = new List <SelectItem>();
            depth--;
            if (depth < 0)
            {
                return;
            }

            var autoExpandNavigationProperties = EdmLibHelpers.GetAutoExpandNavigationProperties(null, baseEntityType,
                                                                                                 model, !isAllSelected, modelBoundQuerySettings);

            foreach (var navigationProperty in autoExpandNavigationProperties)
            {
                IEdmNavigationSource currentEdmNavigationSource =
                    navigationSource.FindNavigationTarget(navigationProperty);

                if (currentEdmNavigationSource != null)
                {
                    List <ODataPathSegment> pathSegments = new List <ODataPathSegment>()
                    {
                        new NavigationPropertySegment(navigationProperty, currentEdmNavigationSource)
                    };

                    ODataExpandPath    expandPath         = new ODataExpandPath(pathSegments);
                    SelectExpandClause selectExpandClause = new SelectExpandClause(new List <SelectItem>(),
                                                                                   true);
                    ExpandedNavigationSelectItem item = new ExpandedNavigationSelectItem(expandPath,
                                                                                         currentEdmNavigationSource, selectExpandClause);
                    modelBoundQuerySettings = EdmLibHelpers.GetModelBoundQuerySettings(navigationProperty,
                                                                                       navigationProperty.ToEntityType(), model);
                    List <SelectItem> nestedSelectItems;
                    List <SelectItem> nestedExpandItems;

                    int maxExpandDepth = GetMaxExpandDepth(modelBoundQuerySettings, navigationProperty.Name);
                    if (maxExpandDepth != 0 && maxExpandDepth < depth)
                    {
                        depth = maxExpandDepth;
                    }

                    GetAutoSelectExpandItems(
                        currentEdmNavigationSource.EntityType(),
                        model,
                        item.NavigationSource,
                        true,
                        modelBoundQuerySettings,
                        depth,
                        out nestedSelectItems,
                        out nestedExpandItems);

                    selectExpandClause = new SelectExpandClause(nestedSelectItems.Concat(nestedExpandItems),
                                                                nestedSelectItems.Count == 0);
                    item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource,
                                                            selectExpandClause);

                    autoExpandItems.Add(item);
                    if (!isAllSelected || autoSelectProperties.Count() != 0)
                    {
                        PathSelectItem pathSelectItem = new PathSelectItem(
                            new ODataSelectPath(pathSegments));
                        autoExpandItems.Add(pathSelectItem);
                    }
                }
            }
        }
        public void ProjectAsWrapper_NonCollection_ProjectedValueNullAndHandleNullPropagationFalse_Throws()
        {
            // Arrange
            _settings.HandleNullPropagation = HandleNullPropagationOption.False;
            ExpandedNavigationSelectItem expandItem = new ExpandedNavigationSelectItem(
                new ODataExpandPath(new NavigationPropertySegment(_model.Order.NavigationProperties().Single(), entitySet: _model.Customers)),
                _model.Customers,
                selectExpandOption: null);
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[] { expandItem }, allSelected: true);
            Expression source = Expression.Constant(null, typeof(Order));

            // Act
            Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order);

            // Assert
            var e = Assert.Throws<TargetInvocationException>(
                () => Expression.Lambda(projection).Compile().DynamicInvoke());
            Assert.IsType<NullReferenceException>(e.InnerException);
        }
예제 #37
0
        // Process $levels in ExpandedNavigationSelectItem.
        private static ExpandedNavigationSelectItem ProcessLevels(
            ExpandedNavigationSelectItem expandItem,
            int levelsMaxLiteralExpansionDepth,
            out bool levelsEncounteredInExpand,
            out bool isMaxLevelInExpand)
        {
            int level;

            isMaxLevelInExpand = false;

            if (expandItem.LevelsOption == null)
            {
                levelsEncounteredInExpand = false;
                level = 1;
            }
            else
            {
                levelsEncounteredInExpand = true;
                if (expandItem.LevelsOption.IsMaxLevel)
                {
                    isMaxLevelInExpand = true;
                    level = levelsMaxLiteralExpansionDepth;
                }
                else
                {
                    level = (int)expandItem.LevelsOption.Level;
                }
            }

            // Do not expand when:
            // 1. $levels is equal to or less than 0.
            // 2. $levels value is greater than current MaxExpansionDepth
            if (level <= 0 || level > levelsMaxLiteralExpansionDepth)
            {
                return(null);
            }

            ExpandedNavigationSelectItem item = null;
            SelectExpandClause           currentSelectExpandClause = null;
            SelectExpandClause           selectExpandClause        = null;
            bool levelsEncounteredInInnerExpand = false;
            bool isMaxLevelInInnerExpand        = false;

            // Try diffent expansion depth until expandItem.SelectAndExpand is successfully expanded
            while (selectExpandClause == null && level > 0)
            {
                selectExpandClause = ProcessLevels(
                    expandItem.SelectAndExpand,
                    levelsMaxLiteralExpansionDepth - level,
                    out levelsEncounteredInInnerExpand,
                    out isMaxLevelInInnerExpand);
                level--;
            }

            if (selectExpandClause == null)
            {
                return(null);
            }

            // Correct level value
            level++;

            while (level > 0)
            {
                if (item == null)
                {
                    currentSelectExpandClause = selectExpandClause;
                }
                else if (selectExpandClause.AllSelected)
                {
                    // Concat the processed items
                    currentSelectExpandClause = new SelectExpandClause(
                        new SelectItem[] { item }.Concat(selectExpandClause.SelectedItems),
                        selectExpandClause.AllSelected);
                }
                else
                {
                    // PathSelectItem is needed for the expanded item if AllSelected is false.
                    PathSelectItem pathSelectItem = new PathSelectItem(
                        new ODataSelectPath(expandItem.PathToNavigationProperty));

                    // Keep default SelectItems before expanded item to keep consistent with normal SelectExpandClause
                    SelectItem[] items = new SelectItem[] { item, pathSelectItem };
                    currentSelectExpandClause = new SelectExpandClause(
                        new SelectItem[] { }.Concat(selectExpandClause.SelectedItems).Concat(items),
                        selectExpandClause.AllSelected);
                }

                // Construct a new ExpandedNavigationSelectItem with current SelectExpandClause.
                item = new ExpandedNavigationSelectItem(
                    expandItem.PathToNavigationProperty,
                    expandItem.NavigationSource,
                    currentSelectExpandClause);

                level--;

                // Need expand and construct selectExpandClause every time if it is max level in inner expand
                if (isMaxLevelInInnerExpand)
                {
                    selectExpandClause = ProcessLevels(
                        expandItem.SelectAndExpand,
                        levelsMaxLiteralExpansionDepth - level,
                        out levelsEncounteredInInnerExpand,
                        out isMaxLevelInInnerExpand);
                }
            }

            levelsEncounteredInExpand = levelsEncounteredInExpand || levelsEncounteredInInnerExpand;
            isMaxLevelInExpand        = isMaxLevelInExpand || isMaxLevelInInnerExpand;

            return(item);
        }
        public void ProjectAsWrapper_Collection_ContainsRightInstance()
        {
            // Arrange
            Order[] orders = new Order[] { new Order() };
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[0], allSelected: true);
            Expression source = Expression.Constant(orders);

            // Act
            Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order);

            // Assert
            IEnumerable<SelectExpandWrapper<Order>> projectedOrders = Expression.Lambda(projection).Compile().DynamicInvoke() as IEnumerable<SelectExpandWrapper<Order>>;
            Assert.NotNull(projectedOrders);
            Assert.Same(orders[0], projectedOrders.Single().Instance);
        }
        public void CreateODataFeed_Ignores_InlineCount_ForInnerFeeds()
        {
            // Arrange
            ODataFeedSerializer serializer = new ODataFeedSerializer(new DefaultODataSerializerProvider());
            HttpRequestMessage request = new HttpRequestMessage();
            request.SetInlineCount(42);
            var result = new object[0];
            IEdmNavigationProperty navProp = new Mock<IEdmNavigationProperty>().Object;
            SelectExpandClause selectExpandClause = new SelectExpandClause(new SelectItem[0], allSelected: true);
            EntityInstanceContext entity = new EntityInstanceContext
            {
                SerializerContext = new ODataSerializerContext { Request = request, EntitySet = _customerSet }
            };
            ODataSerializerContext nestedContext = new ODataSerializerContext(entity, selectExpandClause, navProp);

            // Act
            ODataFeed feed = serializer.CreateODataFeed(result, _customersType, nestedContext);

            // Assert
            Assert.Null(feed.Count);
        }
        public void ProjectAsWrapper_Collection_AppliesPageSize()
        {
            // Arrange
            int pageSize = 5;
            var orders = Enumerable.Range(0, 10).Select(i => new Order());
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[0], allSelected: true);
            Expression source = Expression.Constant(orders);
            _settings.PageSize = pageSize;

            // Act
            Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order);

            // Assert
            IEnumerable<SelectExpandWrapper<Order>> projectedOrders = Expression.Lambda(projection).Compile().DynamicInvoke() as IEnumerable<SelectExpandWrapper<Order>>;
            Assert.NotNull(projectedOrders);
            Assert.Equal(pageSize + 1, projectedOrders.Count());
        }
예제 #41
0
 internal AggregationBinderEFFake(ODataQuerySettings settings, IWebApiAssembliesResolver assembliesResolver, Type elementType, IEdmModel model, TransformationNode transformation, ODataQueryContext context, SelectExpandClause selectExpandClause = null)
     : base(settings, assembliesResolver, elementType, model, transformation, context, selectExpandClause)
 {
 }
        public void ProjectAsWrapper_NullExpandedProperty_HasNullValueInProjectedWrapper()
        {
            // Arrange
            Order order = new Order();
            ExpandedNavigationSelectItem expandItem = new ExpandedNavigationSelectItem(
                new ODataExpandPath(new NavigationPropertySegment(_model.Order.NavigationProperties().Single(), entitySet: _model.Customers)),
                _model.Customers,
                selectExpandOption: null);
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[] { expandItem }, allSelected: true);
            Expression source = Expression.Constant(order);

            // Act
            Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order);

            // Assert
            SelectExpandWrapper<Order> projectedOrder = Expression.Lambda(projection).Compile().DynamicInvoke() as SelectExpandWrapper<Order>;
            Assert.NotNull(projectedOrder);
            Assert.Contains("Customer", projectedOrder.Container.ToDictionary().Keys);
            Assert.Null(projectedOrder.Container.ToDictionary()["Customer"]);
        }
예제 #43
0
        /// <summary>
        /// Generate delta token and save (delta token, delta query) mapping
        /// </summary>
        /// <param name="query">Delta query</param>
        /// <returns>Delta token</returns>
        public static string GenerateDeltaToken(Uri query, IEnumerable entries, IEdmNavigationSource entitySource, SelectExpandClause selectExpandClause)
        {
            // TODO [lianw]: Consider multiple threads here, may need add lock here.
            // TODO [lianw]: May need to optimize here, if $top/$skip/$count

            //var builder = new ODataAnnotationUriBuilder(baseUri);
            var deltaSnapshot = new DeltaSnapshot(query);

            SnapResults(deltaSnapshot.Entries, entries, entitySource, selectExpandClause, string.Empty, string.Empty);
            string deltaToken = deltaSnapshot.TimeStamp.Ticks.ToString(CultureInfo.InvariantCulture);

            DeltaTokenDic[deltaToken] = deltaSnapshot;
            return(deltaToken);
        }
        public void ProjectAsWrapper_Collection_ProjectedValueNullAndHandleNullPropagationTrue()
        {
            // Arrange
            _settings.HandleNullPropagation = HandleNullPropagationOption.True;
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[0], allSelected: true);
            Expression source = Expression.Constant(null, typeof(Order[]));

            // Act
            Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order);

            // Assert
            IEnumerable<SelectExpandWrapper<Order>> projectedOrders = Expression.Lambda(projection).Compile().DynamicInvoke() as IEnumerable<SelectExpandWrapper<Order>>;
            Assert.Null(projectedOrders);
        }
예제 #45
0
        private static void SnapResult(List <DeltaSnapshotEntry> results, object entry, IEdmNavigationSource entitySource, SelectExpandClause selectExpandClause, string parentId, string relationShip)
        {
            var oDataEntry = ODataObjectModelConverter.ConvertToODataEntry(entry, entitySource, ODataVersion.V4);

            results.Add(new DeltaSnapshotEntry(oDataEntry.Id.AbsoluteUri, parentId, relationShip));
            var expandedNavigationItems = selectExpandClause == null ? null : selectExpandClause.SelectedItems.OfType <ExpandedNavigationSelectItem>();

            SnapExpandedEntry(results, entry, entitySource, expandedNavigationItems, oDataEntry.Id.AbsoluteUri);
        }
        public void ProjectAsWrapper_Collection_ProjectedValueNullAndHandleNullPropagationFalse_Throws()
        {
            // Arrange
            _settings.HandleNullPropagation = HandleNullPropagationOption.False;
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[0], allSelected: true);
            Expression source = Expression.Constant(null, typeof(Order[]));

            // Act
            Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order);

            // Assert
            var e = Assert.Throws<TargetInvocationException>(
                () => Expression.Lambda(projection).Compile().DynamicInvoke());
            Assert.IsType<ArgumentNullException>(e.InnerException);
        }
예제 #47
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ODataSerializerContext"/> class.
 /// </summary>
 /// <param name="resource">The resource whose property is being nested.</param>
 /// <param name="selectExpandClause">The <see cref="SelectExpandClause"/> for the property being nested.</param>
 /// <param name="edmProperty">The complex property being nested or the navigation property being expanded.
 /// If the resource property is the dynamic complex, the resource property is null.
 /// </param>
 /// <remarks>This constructor is used to construct the serializer context for writing nested and expanded properties.</remarks>
 public ODataSerializerContext(ResourceContext resource, SelectExpandClause selectExpandClause, IEdmProperty edmProperty)
     : this(resource, edmProperty, null, null)
 {
     SelectExpandClause = selectExpandClause;
 }
        public void ProjectAsWrapper_Element_ProjectedValueContainsModelID()
        {
            // Arrange
            Customer customer = new Customer();
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[0], allSelected: true);
            Expression source = Expression.Constant(customer);

            // Act
            Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Customer);

            // Assert
            SelectExpandWrapper<Customer> customerWrapper = Expression.Lambda(projection).Compile().DynamicInvoke() as SelectExpandWrapper<Customer>;
            Assert.NotNull(customerWrapper.ModelID);
            Assert.Same(_model.Model, ModelContainer.GetModel(customerWrapper.ModelID));
        }
예제 #49
0
        private Expression BuildPropertyContainer(IEdmEntityType elementType, Expression source,
                                                  Dictionary <IEdmNavigationProperty, ExpandedNavigationSelectItem> propertiesToExpand,
                                                  ISet <IEdmStructuralProperty> propertiesToInclude, ISet <IEdmStructuralProperty> autoSelectedProperties, bool isSelectingOpenTypeSegments)
        {
            IList <NamedPropertyExpression> includedProperties = new List <NamedPropertyExpression>();

            foreach (KeyValuePair <IEdmNavigationProperty, ExpandedNavigationSelectItem> kvp in propertiesToExpand)
            {
                IEdmNavigationProperty       propertyToExpand = kvp.Key;
                ExpandedNavigationSelectItem expandItem       = kvp.Value;
                SelectExpandClause           projection       = expandItem.SelectAndExpand;

                Expression propertyName  = CreatePropertyNameExpression(elementType, propertyToExpand, source);
                Expression propertyValue = CreatePropertyValueExpressionWithFilter(elementType, propertyToExpand, source,
                                                                                   expandItem.FilterOption);
                Expression nullCheck = GetNullCheckExpression(propertyToExpand, propertyValue, projection);

                Expression countExpression = CreateTotalCountExpression(propertyValue, expandItem);

                // projection can be null if the expanded navigation property is not further projected or expanded.
                if (projection != null)
                {
                    propertyValue = ProjectAsWrapper(propertyValue, projection, propertyToExpand.ToEntityType(), expandItem.NavigationSource, expandItem);
                }

                NamedPropertyExpression propertyExpression = new NamedPropertyExpression(propertyName, propertyValue);
                if (projection != null)
                {
                    if (!propertyToExpand.Type.IsCollection())
                    {
                        propertyExpression.NullCheck = nullCheck;
                    }
                    else if (_settings.PageSize != null)
                    {
                        propertyExpression.PageSize = _settings.PageSize.Value;
                    }

                    propertyExpression.TotalCount  = countExpression;
                    propertyExpression.CountOption = expandItem.CountOption;
                }

                includedProperties.Add(propertyExpression);
            }

            foreach (IEdmStructuralProperty propertyToInclude in propertiesToInclude)
            {
                Expression propertyName  = CreatePropertyNameExpression(elementType, propertyToInclude, source);
                Expression propertyValue = CreatePropertyValueExpression(elementType, propertyToInclude, source);
                includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue));
            }

            foreach (IEdmStructuralProperty propertyToInclude in autoSelectedProperties)
            {
                Expression propertyName  = CreatePropertyNameExpression(elementType, propertyToInclude, source);
                Expression propertyValue = CreatePropertyValueExpression(elementType, propertyToInclude, source);
                includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue)
                {
                    AutoSelected = true
                });
            }

            if (isSelectingOpenTypeSegments)
            {
                var dynamicPropertyDictionary = EdmLibHelpers.GetDynamicPropertyDictionary(elementType, _model);

                Expression propertyName          = Expression.Constant(dynamicPropertyDictionary.Name);
                Expression propertyValue         = Expression.Property(source, dynamicPropertyDictionary.Name);
                Expression nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue);
                if (_settings.HandleNullPropagation == HandleNullPropagationOption.True)
                {
                    // source == null ? null : propertyValue
                    propertyValue = Expression.Condition(
                        test: Expression.Equal(source, Expression.Constant(value: null)),
                        ifTrue: Expression.Constant(value: null, type: propertyValue.Type.ToNullable()),
                        ifFalse: nullablePropertyValue);
                }
                else
                {
                    propertyValue = nullablePropertyValue;
                }

                includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue));
            }

            // create a property container that holds all these property names and values.
            return(PropertyContainer.CreatePropertyContainer(includedProperties));
        }
        public void ProjectAsWrapper_NonCollection_ContainsRightInstance()
        {
            // Arrange
            Order order = new Order();
            SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[0], allSelected: true);
            Expression source = Expression.Constant(order);

            // Act
            Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order);

            // Assert
            SelectExpandWrapper<Order> projectedOrder = Expression.Lambda(projection).Compile().DynamicInvoke() as SelectExpandWrapper<Order>;
            Assert.NotNull(projectedOrder);
            Assert.Same(order, projectedOrder.Instance);
        }
예제 #51
0
        private static Dictionary <IEdmNavigationProperty, ExpandedNavigationSelectItem> GetPropertiesToExpandInQuery(SelectExpandClause selectExpandClause)
        {
            Dictionary <IEdmNavigationProperty, ExpandedNavigationSelectItem> properties = new Dictionary <IEdmNavigationProperty, ExpandedNavigationSelectItem>();

            foreach (SelectItem selectItem in selectExpandClause.SelectedItems)
            {
                ExpandedNavigationSelectItem expandItem = selectItem as ExpandedNavigationSelectItem;
                if (expandItem != null)
                {
                    SelectExpandNode.ValidatePathIsSupported(expandItem.PathToNavigationProperty);
                    NavigationPropertySegment navigationSegment = expandItem.PathToNavigationProperty.LastSegment as NavigationPropertySegment;
                    if (navigationSegment == null)
                    {
                        throw new ODataException(SRResources.UnsupportedSelectExpandPath);
                    }

                    properties[navigationSegment.NavigationProperty] = expandItem;
                }
            }

            return(properties);
        }
예제 #52
0
 /// <summary>
 /// Creates a new instance of the <see cref="SelectExpandNode"/> class describing the set of structural properties,
 /// nested properties, navigation properties, and actions to select and expand for the given <paramref name="selectExpandClause"/>.
 /// </summary>
 /// <param name="selectExpandClause">The parsed $select and $expand query options.</param>
 /// <param name="structuredType">The structural type of the resource that would be written.</param>
 /// <param name="model">The <see cref="IEdmModel"/> that contains the given structural type.</param>
 public SelectExpandNode(SelectExpandClause selectExpandClause, IEdmStructuredType structuredType, IEdmModel model)
     : this(selectExpandClause, structuredType, model, false)
 {
 }
예제 #53
0
        /// <summary>
        /// Build the expand clause for a given level in the selectExpandClause
        /// </summary>
        /// <param name="selectExpandClause">the current level select expand clause</param>
        /// <param name="firstFlag">whether is inner SelectExpandClause</param>
        /// <returns>the select and expand segment for context url in this level.</returns>
        public string TranslateSelectExpandClause(SelectExpandClause selectExpandClause, bool firstFlag)
        {
            ExceptionUtils.CheckArgumentNotNull(selectExpandClause, "selectExpandClause");

            List <string> selectList   = selectExpandClause.GetCurrentLevelSelectList();
            string        selectClause = null;
            string        expandClause = null;

            if (selectList.Any())
            {
                selectClause = String.Join(ODataConstants.ContextUriProjectionPropertySeparator, selectList.ToArray());
            }

            foreach (SelectItem selectItem in selectExpandClause.SelectedItems)
            {
                if (selectItem is PathSelectItem pathSelectItem)
                {
                    selectClause += this.Translate(pathSelectItem);
                }

                else if (selectItem.GetType() == typeof(ExpandedNavigationSelectItem))
                {
                    if (string.IsNullOrEmpty(expandClause))
                    {
                        expandClause = firstFlag ? expandClause : string.Concat(ExpressionConstants.QueryOptionExpand, ExpressionConstants.SymbolEqual);
                    }
                    else
                    {
                        expandClause += ExpressionConstants.SymbolComma;
                    }

                    expandClause += this.Translate((ExpandedNavigationSelectItem)selectItem);
                }

                else if (selectItem.GetType() == typeof(ExpandedReferenceSelectItem))
                {
                    if (string.IsNullOrEmpty(expandClause))
                    {
                        expandClause = firstFlag ? expandClause : string.Concat(ExpressionConstants.QueryOptionExpand, ExpressionConstants.SymbolEqual);
                    }
                    else
                    {
                        expandClause += ExpressionConstants.SymbolComma;
                    }

                    expandClause += this.Translate((ExpandedReferenceSelectItem)selectItem) + ODataConstants.UriSegmentSeparator + ODataConstants.EntityReferenceSegmentName;
                }
            }

            selectClause = string.IsNullOrEmpty(selectClause) ? null : string.Concat(ExpressionConstants.QueryOptionSelect, ExpressionConstants.SymbolEqual, firstFlag ? Uri.EscapeDataString(selectClause) : selectClause);

            if (string.IsNullOrEmpty(expandClause))
            {
                return(selectClause);
            }
            else
            {
                if (firstFlag)
                {
                    return(string.IsNullOrEmpty(selectClause) ? string.Concat(ExpressionConstants.QueryOptionExpand, ExpressionConstants.SymbolEqual, Uri.EscapeDataString(expandClause)) : string.Concat(selectClause, ExpressionConstants.SymbolQueryConcatenate, ExpressionConstants.QueryOptionExpand, ExpressionConstants.SymbolEqual, Uri.EscapeDataString(expandClause)));
                }
                else
                {
                    return(string.IsNullOrEmpty(selectClause) ? expandClause : string.Concat(selectClause, ";" + expandClause));
                }
            }
        }
예제 #54
0
        public void ProcessLevelsCorrectly_NotAllSelected()
        {
            // Arrange
            var model   = ODataLevelsTest.GetEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("Microsoft.AspNetCore.OData.Tests.Query.LevelsEntity"));

            context.RequestContainer = new MockServiceProvider();
            var selectExpand = new SelectExpandQueryOption(
                select: "Name",
                expand: "Parent($select=ID;$levels=max)",
                context: context);

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            // Level 1.
            Assert.False(clause.AllSelected);
            Assert.Equal(2, clause.SelectedItems.Count());

            var nameSelectItem = Assert.Single(clause.SelectedItems.OfType <PathSelectItem>().Where(
                                                   item => item.SelectedPath.FirstSegment is PropertySegment));

            Assert.Equal("Name", ((PropertySegment)nameSelectItem.SelectedPath.FirstSegment).Property.Name);

            // Before ODL 7.6, the expand navigation property will be added as a select item (PathSelectItem).
            // After ODL 7.6 (include 7.6), the expand navigation property will not be added.
            // Comment the following codes for visibility later.

            /*
             * var parentSelectItem = Assert.Single(clause.SelectedItems.OfType<PathSelectItem>().Where(
             *  item => item.SelectedPath.FirstSegment is NavigationPropertySegment));
             * Assert.Equal(
             *  "Parent",
             *  ((NavigationPropertySegment)parentSelectItem.SelectedPath.FirstSegment).NavigationProperty.Name);
             */
            Assert.Empty(clause.SelectedItems.OfType <PathSelectItem>().Where(item => item.SelectedPath.FirstSegment is NavigationPropertySegment));

            var expandedItem = Assert.Single(clause.SelectedItems.OfType <ExpandedNavigationSelectItem>());

            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)expandedItem.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(expandedItem.LevelsOption);

            // Level 2.
            clause = expandedItem.SelectAndExpand;
            Assert.False(clause.AllSelected);
            Assert.Equal(3, clause.SelectedItems.Count());

            var idSelectItem = Assert.Single(clause.SelectedItems.OfType <PathSelectItem>().Where(
                                                 item => item.SelectedPath.FirstSegment is PropertySegment));

            Assert.Equal("ID", ((PropertySegment)idSelectItem.SelectedPath.FirstSegment).Property.Name);

            var parentSelectItem = Assert.Single(clause.SelectedItems.OfType <PathSelectItem>().Where(
                                                     item => item.SelectedPath.FirstSegment is NavigationPropertySegment));

            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)parentSelectItem.SelectedPath.FirstSegment).NavigationProperty.Name);

            expandedItem = Assert.Single(clause.SelectedItems.OfType <ExpandedNavigationSelectItem>());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)expandedItem.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(expandedItem.LevelsOption);

            clause = expandedItem.SelectAndExpand;
            Assert.False(clause.AllSelected);
            Assert.Single(clause.SelectedItems);

            idSelectItem = Assert.IsType <PathSelectItem>(clause.SelectedItems.Single());
            Assert.Equal("ID", ((PropertySegment)idSelectItem.SelectedPath.FirstSegment).Property.Name);
        }
예제 #55
0
        private void BuildSelections(
            SelectExpandClause selectExpandClause,
            HashSet<IEdmStructuralProperty> allStructuralProperties,
            HashSet<IEdmStructuralProperty> allNestedProperties,
            HashSet<IEdmNavigationProperty> allNavigationProperties,
            HashSet<IEdmAction> allActions,
            HashSet<IEdmFunction> allFunctions)
        {
            foreach (SelectItem selectItem in selectExpandClause.SelectedItems)
            {
                if (selectItem is ExpandedNavigationSelectItem)
                {
                    continue;
                }

                PathSelectItem pathSelectItem = selectItem as PathSelectItem;
                if (pathSelectItem != null)
                {
                    ValidatePathIsSupported(pathSelectItem.SelectedPath);
                    ODataPathSegment segment = pathSelectItem.SelectedPath.LastSegment;

                    NavigationPropertySegment navigationPropertySegment = segment as NavigationPropertySegment;
                    if (navigationPropertySegment != null)
                    {
                        IEdmNavigationProperty navigationProperty = navigationPropertySegment.NavigationProperty;
                        if (allNavigationProperties.Contains(navigationProperty))
                        {
                            SelectedNavigationProperties.Add(navigationProperty);
                        }
                        continue;
                    }

                    PropertySegment structuralPropertySegment = segment as PropertySegment;
                    if (structuralPropertySegment != null)
                    {
                        IEdmStructuralProperty structuralProperty = structuralPropertySegment.Property;
                        if (allStructuralProperties.Contains(structuralProperty))
                        {
                            SelectedStructuralProperties.Add(structuralProperty);
                        }
                        else if (allNestedProperties.Contains(structuralProperty))
                        {
                            SelectedComplexProperties.Add(structuralProperty);
                        }
                        continue;
                    }

                    OperationSegment operationSegment = segment as OperationSegment;
                    if (operationSegment != null)
                    {
                        AddOperations(allActions, allFunctions, operationSegment);
                        continue;
                    }

                    DynamicPathSegment dynamicPathSegment = segment as DynamicPathSegment;
                    if (dynamicPathSegment != null)
                    {
                        SelectedDynamicProperties.Add(dynamicPathSegment.Identifier);
                        continue;
                    }
                    throw new ODataException(Error.Format(SRResources.SelectionTypeNotSupported, segment.GetType().Name));
                }

                WildcardSelectItem wildCardSelectItem = selectItem as WildcardSelectItem;
                if (wildCardSelectItem != null)
                {
                    SelectedStructuralProperties = allStructuralProperties;
                    SelectedComplexProperties = allNestedProperties;
                    SelectedNavigationProperties = allNavigationProperties;
                    SelectAllDynamicProperties = true;
                    continue;
                }

                NamespaceQualifiedWildcardSelectItem wildCardActionSelection = selectItem as NamespaceQualifiedWildcardSelectItem;
                if (wildCardActionSelection != null)
                {
                    SelectedActions = allActions;
                    SelectedFunctions = allFunctions;
                    continue;
                }

                throw new ODataException(Error.Format(SRResources.SelectionTypeNotSupported, selectItem.GetType().Name));
            }
        }
예제 #56
0
        private static void AddPageNextLinkSelectItems(OeModelBoundSettings settings, SelectExpandClause selectExpandClause, ref List <SelectItem> selectItems)
        {
            if (settings != null && (settings.PageSize > 0 || settings.NavigationNextLink))
            {
                if (selectItems == null)
                {
                    selectItems = new List <SelectItem>(selectExpandClause.SelectedItems);
                }

                if (settings.PageSize > 0)
                {
                    selectItems.Add(new Parsers.Translators.OePageSelectItem(settings.PageSize));
                }

                if (settings.NavigationNextLink)
                {
                    selectItems.Add(Parsers.Translators.OeNextLinkSelectItem.Instance);
                }
            }
        }
예제 #57
0
        private void BuildOrderBySkipTake(OeNavigationSelectItem navigationItem, OrderByClause orderByClause, bool hasSelectItems)
        {
            while (orderByClause != null)
            {
                var propertyNode = (SingleValuePropertyAccessNode)orderByClause.Expression;
                if (propertyNode.Source is SingleNavigationNode navigationNode)
                {
                    OeNavigationSelectItem?      match;
                    ExpandedNavigationSelectItem?navigationSelectItem = null;
                    for (; ;)
                    {
                        if ((match = navigationItem.FindHierarchyNavigationItem(navigationNode.NavigationProperty)) != null)
                        {
                            match.AddStructuralItem((IEdmStructuralProperty)propertyNode.Property, true);
                            break;
                        }

                        SelectExpandClause selectExpandClause;
                        if (navigationSelectItem == null)
                        {
                            var pathSelectItem = new PathSelectItem(new ODataSelectPath(new PropertySegment((IEdmStructuralProperty)propertyNode.Property)));
                            selectExpandClause = new SelectExpandClause(new[] { pathSelectItem }, false);
                        }
                        else
                        {
                            selectExpandClause = new SelectExpandClause(new[] { navigationSelectItem }, false);
                        }

                        var segment = new NavigationPropertySegment(navigationNode.NavigationProperty, navigationNode.NavigationSource);
                        navigationSelectItem = new ExpandedNavigationSelectItem(new ODataExpandPath(segment), navigationNode.NavigationSource, selectExpandClause);

                        if (navigationNode.Source is SingleNavigationNode singleNavigationNode)
                        {
                            navigationNode = singleNavigationNode;
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (navigationSelectItem != null)
                    {
                        if (match == null)
                        {
                            match = navigationItem;
                        }

                        var selectItemTranslator = new OeSelectItemTranslator(_edmModel, true);
                        selectItemTranslator.Translate(match, navigationSelectItem);
                    }
                }
                else
                {
                    if (hasSelectItems)
                    {
                        navigationItem.AddStructuralItem((IEdmStructuralProperty)propertyNode.Property, true);
                    }
                }

                orderByClause = orderByClause.ThenBy;
            }
        }
예제 #58
0
 public SelectExpandClause Build(SelectExpandClause selectExpandClause, IEdmEntityType entityType)
 {
     return(selectExpandClause == null ? null : GetSelectItems(selectExpandClause, _modelBoundProvider.GetSettings(entityType)));
 }
        public static void SetSelectExpandClause(this HttpRequestMessage request,
            SelectExpandClause selectExpandClause)
        {
            // Use correct argument name in ArgumentNullException, if any.
            if (selectExpandClause == null)
            {
                throw Error.ArgumentNull("selectExpandClause");
            }

            Extensions.HttpRequestMessageExtensions.ODataProperties(request).SelectExpandClause = selectExpandClause;
        }
        public void ProcessLevelsCorrectly_NotAllSelected()
        {
            // Arrange
            var model   = ODataLevelsTest.GetEdmModel();
            var context = new ODataQueryContext(
                model,
                model.FindDeclaredType("Microsoft.AspNet.OData.Test.Routing.LevelsEntity"));

            context.RequestContainer = new MockContainer();
            var selectExpand = new SelectExpandQueryOption(
                select: "Name",
                expand: "Parent($select=ID;$levels=max)",
                context: context);

            // Act
            SelectExpandClause clause = selectExpand.ProcessLevels();

            // Assert
            // Level 1.
            Assert.False(clause.AllSelected);
            Assert.Equal(3, clause.SelectedItems.Count());

            var nameSelectItem = Assert.Single(clause.SelectedItems.OfType <PathSelectItem>().Where(
                                                   item => item.SelectedPath.FirstSegment is PropertySegment));

            Assert.Equal("Name", ((PropertySegment)nameSelectItem.SelectedPath.FirstSegment).Property.Name);

            var parentSelectItem = Assert.Single(clause.SelectedItems.OfType <PathSelectItem>().Where(
                                                     item => item.SelectedPath.FirstSegment is NavigationPropertySegment));

            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)parentSelectItem.SelectedPath.FirstSegment).NavigationProperty.Name);

            var expandedItem = Assert.Single(clause.SelectedItems.OfType <ExpandedNavigationSelectItem>());

            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)expandedItem.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(expandedItem.LevelsOption);

            // Level 2.
            clause = expandedItem.SelectAndExpand;
            Assert.False(clause.AllSelected);
            Assert.Equal(3, clause.SelectedItems.Count());

            var idSelectItem = Assert.Single(clause.SelectedItems.OfType <PathSelectItem>().Where(
                                                 item => item.SelectedPath.FirstSegment is PropertySegment));

            Assert.Equal("ID", ((PropertySegment)idSelectItem.SelectedPath.FirstSegment).Property.Name);

            parentSelectItem = Assert.Single(clause.SelectedItems.OfType <PathSelectItem>().Where(
                                                 item => item.SelectedPath.FirstSegment is NavigationPropertySegment));
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)parentSelectItem.SelectedPath.FirstSegment).NavigationProperty.Name);

            expandedItem = Assert.Single(clause.SelectedItems.OfType <ExpandedNavigationSelectItem>());
            Assert.Equal(
                "Parent",
                ((NavigationPropertySegment)expandedItem.PathToNavigationProperty.FirstSegment).NavigationProperty.Name);
            Assert.Null(expandedItem.LevelsOption);

            clause = expandedItem.SelectAndExpand;
            Assert.False(clause.AllSelected);
            Assert.Single(clause.SelectedItems);

            idSelectItem = Assert.IsType <PathSelectItem>(clause.SelectedItems.Single());
            Assert.Equal("ID", ((PropertySegment)idSelectItem.SelectedPath.FirstSegment).Property.Name);
        }