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); } }
/// <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); }
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); } } } }
/// <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); } } } }
// 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)); }
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); } }
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); }
// 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); }
/// <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; }
// 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; }
// 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; } }
/// <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);
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; }
// 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); } }
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; }
/// <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)); }
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; }
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'."); }
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); }
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"]); }
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); }
// 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()); }
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"]); }
/// <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); }
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); }
/// <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)); }
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); }
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); }
/// <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) { }
/// <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)); } } }
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); }
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)); } }
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); } } }
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; } }
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); }