public void Validate_DepthChecks_DollarLevels(string expand, int maxExpansionDepth) { // Arrange var validator = new SelectExpandQueryValidator(); var builder = new ODataConventionModelBuilder(); builder.EntitySet<ODataLevelsTest.LevelsEntity>("Entities"); IEdmModel model = builder.GetEdmModel(); var context = new ODataQueryContext(model, typeof(ODataLevelsTest.LevelsEntity)); var selectExpandQueryOption = new SelectExpandQueryOption(null, expand, context); selectExpandQueryOption.LevelsMaxLiteralExpansionDepth = 1; // Act & Assert Assert.Throws<ODataException>( () => validator.Validate( selectExpandQueryOption, new ODataValidationSettings { MaxExpansionDepth = maxExpansionDepth }), String.Format( CultureInfo.CurrentCulture, "The request includes a $expand path which is too deep. The maximum depth allowed is {0}. " + "To increase the limit, set the 'MaxExpansionDepth' property on EnableQueryAttribute or ODataValidationSettings.", maxExpansionDepth)); Assert.DoesNotThrow( () => validator.Validate( selectExpandQueryOption, new ODataValidationSettings { MaxExpansionDepth = maxExpansionDepth + 1 })); }
/// <summary> /// Validates a <see cref="TopQueryOption" />. /// </summary> /// <param name="selectExpandQueryOption">The $select and $expand query.</param> /// <param name="validationSettings">The validation settings.</param> public virtual void Validate(SelectExpandQueryOption selectExpandQueryOption, ODataValidationSettings validationSettings) { if (selectExpandQueryOption == null) { throw Error.ArgumentNull("selectExpandQueryOption"); } if (validationSettings == null) { throw Error.ArgumentNull("validationSettings"); } IEdmModel model = selectExpandQueryOption.Context.Model; ValidateRestrictions(selectExpandQueryOption.SelectExpandClause, model); if (validationSettings.MaxExpansionDepth > 0) { if (selectExpandQueryOption.LevelsMaxLiteralExpansionDepth > validationSettings.MaxExpansionDepth) { throw new ODataException(Error.Format( SRResources.InvalidExpansionDepthValue, "LevelsMaxLiteralExpansionDepth", "MaxExpansionDepth")); } ValidateDepth(selectExpandQueryOption.SelectExpandClause, validationSettings.MaxExpansionDepth); } }
public static object Bind(object entity, ODataQuerySettings settings, SelectExpandQueryOption selectExpandQuery) { Contract.Assert(entity != null); SelectExpandBinder binder = new SelectExpandBinder(settings, selectExpandQuery); return binder.Bind(entity); }
public void Bind_GeneratedExpression_ContainsExpandedObject() { // Arrange SelectExpandQueryOption selectExpand = new SelectExpandQueryOption("Orders", "Orders,Orders($expand=Customer)", _context); IPropertyMapper mapper = new IdentityPropertyMapper(); _model.Model.SetAnnotationValue(_model.Order, new DynamicPropertyDictionaryAnnotation(typeof(Order).GetProperty("OrderProperties"))); // Act IQueryable queryable = SelectExpandBinder.Bind(_queryable, _settings, new DefaultAssembliesResolver(), selectExpand); // Assert IEnumerator enumerator = queryable.GetEnumerator(); Assert.True(enumerator.MoveNext()); var partialCustomer = Assert.IsAssignableFrom<SelectExpandWrapper<Customer>>(enumerator.Current); Assert.False(enumerator.MoveNext()); Assert.Null(partialCustomer.Instance); IEnumerable<SelectExpandWrapper<Order>> innerOrders = partialCustomer.Container .ToDictionary(mapper)["Orders"] as IEnumerable<SelectExpandWrapper<Order>>; Assert.NotNull(innerOrders); SelectExpandWrapper<Order> partialOrder = innerOrders.Single(); Assert.Same(_queryable.First().Orders.First(), partialOrder.Instance); object customer = partialOrder.Container.ToDictionary(mapper)["Customer"]; SelectExpandWrapper<Customer> innerInnerCustomer = Assert.IsAssignableFrom<SelectExpandWrapper<Customer>>(customer); Assert.Same(_queryable.First(), innerInnerCustomer.Instance); }
public static IQueryable Bind(IQueryable queryable, ODataQuerySettings settings, SelectExpandQueryOption selectExpandQuery) { Contract.Assert(queryable != null); SelectExpandBinder binder = new SelectExpandBinder(settings, selectExpandQuery); return binder.Bind(queryable); }
public void ValidateDoesNotThrow_IfExpansionDepthIsZero() { string expand = "Orders/Customer/Orders/Customer/Orders/Customer"; SelectExpandQueryValidator validator = new SelectExpandQueryValidator(); SelectExpandQueryOption selectExpandQueryOption = new SelectExpandQueryOption(null, expand, _queryContext); Assert.DoesNotThrow( () => validator.Validate(selectExpandQueryOption, new ODataValidationSettings { MaxExpansionDepth = 0 })); }
public void ValidateThrowException_IfNotNavigable() { CustomersModelWithInheritance model = new CustomersModelWithInheritance(); model.Model.SetAnnotationValue(model.Customer, new ClrTypeAnnotation(typeof(Customer))); ODataQueryContext queryContext = new ODataQueryContext(model.Model, typeof(Customer)); model.Model.SetAnnotationValue(model.Customer.FindProperty("Orders"), new QueryableRestrictionsAnnotation(new QueryableRestrictions{NotNavigable=true})); string select = "Orders"; SelectExpandQueryValidator validator = new SelectExpandQueryValidator(); SelectExpandQueryOption selectExpandQueryOption = new SelectExpandQueryOption(select, null, queryContext); Assert.Throws<ODataException>( () => validator.Validate(selectExpandQueryOption, new ODataValidationSettings()), "The property 'Orders' cannot be used for navigation."); }
public SelectExpandBinder(ODataQuerySettings settings, SelectExpandQueryOption selectExpandQuery) { Contract.Assert(settings != null); Contract.Assert(selectExpandQuery != null); Contract.Assert(selectExpandQuery.Context != null); Contract.Assert(selectExpandQuery.Context.Model != null); Contract.Assert(settings.HandleNullPropagation != HandleNullPropagationOption.Default); _selectExpandQuery = selectExpandQuery; _context = selectExpandQuery.Context; _model = _context.Model; _modelID = ModelContainer.GetModelID(_model); _settings = settings; }
public void Bind_ReturnsIEdmObject_WithRightEdmType() { // Arrange SelectExpandQueryOption selectExpand = new SelectExpandQueryOption(select: "ID", expand: null, context: _context); // Act IQueryable queryable = SelectExpandBinder.Bind(_queryable, _settings, selectExpand); // Assert Assert.NotNull(queryable); IEdmTypeReference edmType = _model.Model.GetEdmTypeReference(queryable.GetType()); Assert.NotNull(edmType); Assert.True(edmType.IsCollection()); Assert.Same(_model.Customer, edmType.AsCollection().ElementType().Definition); }
public void Validate_DepthChecks(string expand, int maxExpansionDepth) { // Arrange SelectExpandQueryValidator validator = new SelectExpandQueryValidator(); SelectExpandQueryOption selectExpandQueryOption = new SelectExpandQueryOption(null, expand, _queryContext); // Act & Assert Assert.Throws<ODataException>( () => validator.Validate(selectExpandQueryOption, new ODataValidationSettings { MaxExpansionDepth = maxExpansionDepth }), String.Format(CultureInfo.CurrentCulture, "The request includes a $expand path which is too deep. The maximum depth allowed is {0}. " + "To increase the limit, set the 'MaxExpansionDepth' property on EnableQueryAttribute or ODataValidationSettings.", maxExpansionDepth)); Assert.DoesNotThrow( () => validator.Validate(selectExpandQueryOption, new ODataValidationSettings { MaxExpansionDepth = maxExpansionDepth + 1 })); }
public void ValidateThrowException_IfBaseOrDerivedClassPropertyNotNavigable(string className, string propertyName) { CustomersModelWithInheritance model = new CustomersModelWithInheritance(); model.Model.SetAnnotationValue(model.SpecialCustomer, new ClrTypeAnnotation(typeof(Customer))); ODataQueryContext queryContext = new ODataQueryContext(model.Model, typeof(Customer)); EdmEntityType classType = (className == "Customer") ? model.Customer : model.SpecialCustomer; model.Model.SetAnnotationValue(classType.FindProperty(propertyName), new QueryableRestrictionsAnnotation(new QueryableRestrictions { NotNavigable = true })); string select = "NS.SpecialCustomer/" + propertyName; SelectExpandQueryValidator validator = new SelectExpandQueryValidator(); SelectExpandQueryOption selectExpandQueryOption = new SelectExpandQueryOption(select, null, queryContext); Assert.Throws<ODataException>( () => validator.Validate(selectExpandQueryOption, new ODataValidationSettings()), String.Format(CultureInfo.InvariantCulture, "The property '{0}' cannot be used for navigation.", propertyName)); }
/// <summary> /// Validates a <see cref="TopQueryOption" />. /// </summary> /// <param name="selectExpandQueryOption">The $select and $expand query.</param> /// <param name="validationSettings">The validation settings.</param> public virtual void Validate(SelectExpandQueryOption selectExpandQueryOption, ODataValidationSettings validationSettings) { if (selectExpandQueryOption == null) { throw Error.ArgumentNull("selectExpandQueryOption"); } if (validationSettings == null) { throw Error.ArgumentNull("validationSettings"); } if (validationSettings.MaxExpansionDepth > 0) { ValidateDepth(selectExpandQueryOption.SelectExpandClause, validationSettings.MaxExpansionDepth); } }
/// <summary> /// Validates a <see cref="TopQueryOption" />. /// </summary> /// <param name="selectExpandQueryOption">The $select and $expand query.</param> /// <param name="validationSettings">The validation settings.</param> public virtual void Validate(SelectExpandQueryOption selectExpandQueryOption, ODataValidationSettings validationSettings) { if (selectExpandQueryOption == null) { throw Error.ArgumentNull("selectExpandQueryOption"); } if (validationSettings == null) { throw Error.ArgumentNull("validationSettings"); } IEdmModel model = selectExpandQueryOption.Context.Model; ValidateRestrictions(selectExpandQueryOption.SelectExpandClause, model); if (validationSettings.MaxExpansionDepth > 0) { ValidateDepth(selectExpandQueryOption.SelectExpandClause, validationSettings.MaxExpansionDepth); } }
public void Bind_GeneratedExpression_ContainsExpandedObject() { // Arrange SelectExpandQueryOption selectExpand = new SelectExpandQueryOption("Orders,Orders/Customer", "Orders,Orders/Customer", _context); // Act IQueryable queryable = SelectExpandBinder.Bind(_queryable, _settings, selectExpand); // Assert IEnumerator enumerator = queryable.GetEnumerator(); Assert.True(enumerator.MoveNext()); var partialCustomer = Assert.IsAssignableFrom<SelectExpandWrapper<Customer>>(enumerator.Current); Assert.False(enumerator.MoveNext()); Assert.Null(partialCustomer.Instance); IEnumerable<SelectExpandWrapper<Order>> innerOrders = partialCustomer.Container.ToDictionary()["Orders"] as IEnumerable<SelectExpandWrapper<Order>>; Assert.NotNull(innerOrders); SelectExpandWrapper<Order> partialOrder = innerOrders.Single(); Assert.Same(_queryable.First().Orders.First(), partialOrder.Instance); SelectExpandWrapper<Customer> innerInnerCustomer = Assert.IsAssignableFrom<SelectExpandWrapper<Customer>>(partialOrder.Container.ToDictionary()["Customer"]); Assert.Same(_queryable.First(), innerInnerCustomer.Instance); }
public void Validate_Throws_LevelsMaxLiteralExpansionDepthGreaterThanMaxExpansionDepth() { // Arrange string expand = "Parent($levels=2)"; var validator = new SelectExpandQueryValidator(); var builder = new ODataConventionModelBuilder(); builder.EntitySet<ODataLevelsTest.LevelsEntity>("Entities"); IEdmModel model = builder.GetEdmModel(); var context = new ODataQueryContext(model, typeof(ODataLevelsTest.LevelsEntity)); var selectExpandQueryOption = new SelectExpandQueryOption(null, expand, context); selectExpandQueryOption.LevelsMaxLiteralExpansionDepth = 4; // Act & Assert Assert.Throws<ODataException>( () => validator.Validate( selectExpandQueryOption, new ODataValidationSettings { MaxExpansionDepth = 3 }), "'LevelsMaxLiteralExpansionDepth' should be less than or equal to 'MaxExpansionDepth'."); }
private static StringBuilder ODataContextUriBuilder(string scheme, string host, string path, EntitySet entitySet, SelectExpandQueryOption selectQueryOption) { StringBuilder contextUriBuilder = ODataContextUriBuilder(scheme, host, path, entitySet); if (selectQueryOption?.RawValue.Equals("$select=*", StringComparison.Ordinal) == true) { contextUriBuilder.Append("(*)"); } else if (selectQueryOption?.PropertyPaths.Count > 0) { contextUriBuilder.AppendFormat(CultureInfo.InvariantCulture, "({0})", string.Join(",", selectQueryOption.PropertyPaths.Select(p => p.Property.Name))); } return(contextUriBuilder); }
/// <summary> /// Returns a <see cref="string"/> containing the the @odata.context. /// </summary> /// <param name="metadataLevel">The OData metadata level for the current request.</param> /// <param name="scheme">The scheme, which should be HTTP or HTTPS.</param> /// <param name="host">The host (e.g. odataservice.org).</param> /// <param name="path">The path (e.g. /odata/...)</param> /// <param name="entitySet">The <see cref="EntitySet"/>.</param> /// <param name="selectQueryOption">The $select query option.</param> /// <returns>A <see cref="string"/> containing the the @odata.context.</returns> public static string ODataContext(ODataMetadataLevel metadataLevel, string scheme, string host, string path, EntitySet entitySet, SelectExpandQueryOption selectQueryOption) => metadataLevel != ODataMetadataLevel.None ? ODataContextUriBuilder(scheme, host, path, entitySet, selectQueryOption).ToString() : default;
public void ProcessLevelsCorrectly_WithNestedLevels() { // 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: 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); }
public void ProcessLevelsCorrectly_WithMultipleProperties() { // 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: 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 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); }
public static bool IsValid(SelectExpandQueryOption selectExpandQueryOption) { return(selectExpandQueryOption?.SelectExpandClause?.SelectedItems != null); }
public SelectExpandBinder(ODataQuerySettings settings, IAssemblyProvider assembliesProvider, SelectExpandQueryOption selectExpandQuery) { Contract.Assert(settings != null); Contract.Assert(assembliesProvider != null); Contract.Assert(selectExpandQuery != null); Contract.Assert(selectExpandQuery.Context != null); Contract.Assert(selectExpandQuery.Context.Model != null); Contract.Assert(settings.HandleNullPropagation != HandleNullPropagationOption.Default); _selectExpandQuery = selectExpandQuery; _context = selectExpandQuery.Context; _model = _context.Model; _modelID = ModelContainer.GetModelID(_model); _settings = settings; _assemblyProvider = assembliesProvider; }
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); }
public async Task <IActionResult> OData(ODataQueryOptions <DeveloperDto> oDataQuery) { var edmModel = EdmModelConfig.GetEdmModel(); var edmEntitySet = edmModel.FindDeclaredEntitySet(nameof(Developer)); var context = new ODataQueryContext(edmModel, typeof(Developer), oDataQuery.Context.Path); var edmType = context.ElementType; var parameters = new Dictionary <string, string>(); if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.Filter)) { parameters.Add("$filter", oDataQuery.RawValues.Filter); } if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.Expand)) { parameters.Add("$expand", oDataQuery.RawValues.Expand); } if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.OrderBy)) { parameters.Add("$orderby", oDataQuery.RawValues.OrderBy); } var parser = new ODataQueryOptionParser(edmModel, edmType, edmEntitySet, parameters); var queryable = (IQueryable <Developer>)_databaseContext.Developer; if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.Filter)) { var filter = new FilterQueryOption(oDataQuery.RawValues.Filter, context, parser); queryable = (IQueryable <Developer>)filter.ApplyTo(queryable, new ODataQuerySettings()); } if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.OrderBy)) { var orderBy = new OrderByQueryOption(oDataQuery.RawValues.OrderBy, context, parser); queryable = orderBy.ApplyTo(queryable, new ODataQuerySettings()); } IQueryable <object> expandableQueryable = null; if (!string.IsNullOrWhiteSpace(oDataQuery.RawValues.Expand)) { var expand = new SelectExpandQueryOption(null, oDataQuery.RawValues.Expand, context, parser); expandableQueryable = (IQueryable <object>)expand.ApplyTo(queryable, new ODataQuerySettings()); } int pageIndex = 1; var hasPageIndex = oDataQuery.Request.Query.TryGetValue("$pageindex", out StringValues pageIndexRaw); if (hasPageIndex) { var isTrue = int.TryParse(pageIndexRaw, out int _pageIndexRaw); pageIndex = (isTrue && _pageIndexRaw > 0) ? _pageIndexRaw : pageIndex; } int pageSize = 10; var hasPageSize = oDataQuery.Request.Query.TryGetValue("$pagesize", out StringValues pageSizeRaw); if (hasPageSize) { var isTrue = int.TryParse(pageSizeRaw, out int _pageSizeRaw); pageSize = (isTrue && _pageSizeRaw > 0) ? _pageSizeRaw : pageSize; } IQueryable <object> queryToExecute = expandableQueryable ?? queryable; var records = await queryToExecute.Skip((pageIndex - 1) *pageSize).Take(pageSize).ToListAsync(); var count = await queryToExecute.CountAsync(); var pageList = new PageList <Developer>(MapDomain(records).ToList(), count, pageIndex, pageSize); var response = PageListDto <DeveloperDto> .Map(pageList, DeveloperDto.MapDomainToDto); return(Ok(response)); }
public void Validate_Throw_WithInvalidMaxExpansionDepth() { int maxExpansionDepth = -1; // Arrange string expand = "Parent($levels=1)"; var validator = new SelectExpandQueryValidator(); var builder = new ODataConventionModelBuilder(); builder.EntitySet<ODataLevelsTest.LevelsEntity>("Entities"); IEdmModel model = builder.GetEdmModel(); var context = new ODataQueryContext(model, typeof(ODataLevelsTest.LevelsEntity)); var selectExpandQueryOption = new SelectExpandQueryOption(null, expand, context); // Act & Assert Assert.Throws<ArgumentOutOfRangeException>( () => validator.Validate( selectExpandQueryOption, new ODataValidationSettings { MaxExpansionDepth = maxExpansionDepth }), "Value must be greater than or equal to 0.\r\nParameter name: value\r\nActual value was -1."); }
public void ValidateDoesNotThrow_IfExpansionDepthIsZero_DollarLevels() { // Arrange string expand = "Parent($expand=Parent($expand=Parent($levels=10)))"; var validator = new SelectExpandQueryValidator(); var builder = new ODataConventionModelBuilder(); builder.EntitySet<ODataLevelsTest.LevelsEntity>("Entities"); IEdmModel model = builder.GetEdmModel(); var context = new ODataQueryContext(model, typeof(ODataLevelsTest.LevelsEntity)); var selectExpandQueryOption = new SelectExpandQueryOption(null, expand, context); // Act & Assert Assert.DoesNotThrow( () => validator.Validate( selectExpandQueryOption, new ODataValidationSettings { MaxExpansionDepth = 0 })); }
public void ValidateDoesNotThrow_LevelsMaxLiteralExpansionDepthAndMaxExpansionDepth( int levelsMaxLiteralExpansionDepth, int maxExpansionDepth) { // Arrange string expand = "Parent($levels=2)"; var validator = new SelectExpandQueryValidator(); var builder = new ODataConventionModelBuilder(); builder.EntitySet<ODataLevelsTest.LevelsEntity>("Entities"); IEdmModel model = builder.GetEdmModel(); var context = new ODataQueryContext(model, typeof(ODataLevelsTest.LevelsEntity)); var selectExpandQueryOption = new SelectExpandQueryOption(null, expand, context); selectExpandQueryOption.LevelsMaxLiteralExpansionDepth = levelsMaxLiteralExpansionDepth; // Act & Assert Assert.DoesNotThrow( () => validator.Validate( selectExpandQueryOption, new ODataValidationSettings { MaxExpansionDepth = maxExpansionDepth })); }
public static IQueryable Bind(IQueryable queryable, ODataQuerySettings settings, SelectExpandQueryOption selectExpandQuery) { Contract.Assert(queryable != null); SelectExpandBinder binder = new SelectExpandBinder(settings, selectExpandQuery); return(binder.Bind(queryable)); }
/// <summary> /// Resolves the @odata.context URI for the specified request and Entity Set and select query option. /// </summary> /// <param name="request">The HTTP request message which led to this OData request.</param> /// <param name="entitySet">The EntitySet used in the request.</param> /// <param name="selectExpandQueryOption">The select query option.</param> /// <returns>A <see cref="Uri"/> containing the @odata.context URI, or null if the metadata for the request is none.</returns> public static Uri ResolveODataContextUri(this HttpRequestMessage request, EntitySet entitySet, SelectExpandQueryOption selectExpandQueryOption) { var requestOptions = request.ReadODataRequestOptions(); if (requestOptions.MetadataLevel == ODataMetadataLevel.None) { return(null); } return(new Uri(request.RequestUri.ODataContextUriBuilder(entitySet, selectExpandQueryOption).ToString())); }
public static ICollection <string> GetExpandedFields(this SelectExpandQueryOption selectExpandQueryOption) { return(GetExpandedFields(selectExpandQueryOption.SelectExpandClause.SelectedItems)); }
internal static StringBuilder ODataContextUriBuilder(this Uri requestUri, EntitySet entitySet, SelectExpandQueryOption selectExpandQueryOption) { var contextUriBuilder = ODataContextUriBuilder(requestUri); contextUriBuilder.Append("#").Append(entitySet.Name); if (selectExpandQueryOption?.RawValue.Equals("$select=*") == true) { contextUriBuilder.Append("(*)"); } else if (selectExpandQueryOption?.Properties.Count > 0) { contextUriBuilder.AppendFormat("({0})", string.Join(",", selectExpandQueryOption.Properties)); } return(contextUriBuilder); }
public void Bind_GeneratedExpression_CheckNullObjectWithinChainProjectionByKey() { // Arrange SelectExpandQueryOption selectExpand = new SelectExpandQueryOption(null, "Orders($expand=Customer($select=City))", _context); _model.Model.SetAnnotationValue(_model.Order, new DynamicPropertyDictionaryAnnotation(typeof(Order).GetProperty("OrderProperties"))); // Act IQueryable queryable = SelectExpandBinder.Bind(_queryable, _settings, new DefaultAssembliesResolver(), selectExpand); // Assert var unaryExpression = (UnaryExpression)((MethodCallExpression)queryable.Expression).Arguments.Single(a => a is UnaryExpression); var expressionString = unaryExpression.Operand.ToString(); Assert.Contains("IsNull = (Convert(Param_1.Customer.ID) == null)", expressionString); }