private void ParseUriAndVerify( Uri uri, Action <ODataPath, FilterClause, OrderByClause, SelectExpandClause, IDictionary <string, SingleValueNode> > verifyAction) { // run 2 test passes: // 1. low level api - ODataUriParser instance methods { List <CustomQueryOptionToken> queries = UriUtils.ParseQueryOptions(uri); ODataUriParser parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("http://gobbledygook/"), uri); ODataPath path = parser.ParsePath(); IEdmNavigationSource entitySource = ResolveEntitySource(path); IEdmEntitySet entitySet = entitySource as IEdmEntitySet; var dic = queries.ToDictionary(customQueryOptionToken => customQueryOptionToken.Name, customQueryOptionToken => queries.GetQueryOptionValue(customQueryOptionToken.Name)); ODataQueryOptionParser queryOptionParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, entitySet.EntityType(), entitySet, dic) { Configuration = { ParameterAliasValueAccessor = parser.ParameterAliasValueAccessor } }; FilterClause filterClause = queryOptionParser.ParseFilter(); SelectExpandClause selectExpandClause = queryOptionParser.ParseSelectAndExpand(); OrderByClause orderByClause = queryOptionParser.ParseOrderBy(); // Two parser should share same ParameterAliasNodes verifyAction(path, filterClause, orderByClause, selectExpandClause, parser.ParameterAliasNodes); verifyAction(path, filterClause, orderByClause, selectExpandClause, queryOptionParser.ParameterAliasNodes); } //2. high level api - ParseUri { ODataUriParser parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("http://gobbledygook/"), uri); verifyAction(parser.ParsePath(), parser.ParseFilter(), parser.ParseOrderBy(), parser.ParseSelectAndExpand(), parser.ParameterAliasNodes); } }
public void QueryOptionWithNullValueShouldWork() { var uriParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet(), new Dictionary <string, string>() { { "$filter", null }, { "$expand", null }, { "$select", null }, { "$orderby", null }, { "$top", null }, { "$skip", null }, { "index", null }, { "$count", null }, { "$search", null }, { "$compute", null }, { "$unknow", null }, }); uriParser.ParseFilter().Should().BeNull(); uriParser.ParseSelectAndExpand().Should().BeNull(); uriParser.ParseOrderBy().Should().BeNull(); uriParser.ParseTop().Should().Be(null); uriParser.ParseSkip().Should().Be(null); uriParser.ParseIndex().Should().Be(null); uriParser.ParseCount().Should().Be(null); uriParser.ParseSearch().Should().BeNull(); uriParser.ParseCompute().Should().BeNull(); }
public void CreatePropertyValueExpressionWithFilter_Single_Works_IfSettingIsOff() { // Arrange _settings.HandleReferenceNavigationPropertyExpandFilter = false; var order = Expression.Constant( new Order { Customer = new Customer { ID = 1 } } ); var customerProperty = _model.Order.NavigationProperties().Single(p => p.Name == "Customer"); var parser = new ODataQueryOptionParser( _model.Model, _model.Customer, _model.Customers, new Dictionary <string, string> { { "$filter", "ID ne 1" } }); var filterCaluse = parser.ParseFilter(); // Act var filterInExpand = _binder.CreatePropertyValueExpressionWithFilter(_model.Order, customerProperty, order, filterCaluse); // Assert var customer = Expression.Lambda(filterInExpand).Compile().DynamicInvoke() as Customer; Assert.NotNull(customer); Assert.Equal(1, customer.ID); }
public void QueryOptionWithEmptyValueShouldWork() { var uriParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet(), new Dictionary <string, string>() { { "$filter", "" }, { "$expand", "" }, { "$select", "" }, { "$orderby", "" }, { "$top", "" }, { "$skip", "" }, { "$count", "" }, { "$search", "" }, { "$unknow", "" }, }); uriParser.ParseFilter().Should().BeNull(); var results = uriParser.ParseSelectAndExpand(); results.AllSelected.Should().BeTrue(); results.SelectedItems.Should().HaveCount(0); uriParser.ParseOrderBy().Should().BeNull(); Action action = () => uriParser.ParseTop(); action.ShouldThrow <ODataException>().WithMessage(Strings.SyntacticTree_InvalidTopQueryOptionValue("")); action = () => uriParser.ParseSkip(); action.ShouldThrow <ODataException>().WithMessage(Strings.SyntacticTree_InvalidSkipQueryOptionValue("")); action = () => uriParser.ParseCount(); action.ShouldThrow <ODataException>().WithMessage(Strings.ODataUriParser_InvalidCount("")); action = () => uriParser.ParseSearch(); action.ShouldThrow <ODataException>().WithMessage(Strings.UriQueryExpressionParser_ExpressionExpected(0, "")); }
public void CreatePropertyValueExpressionWithFilter_Collection_ThrowsODataException_IfMappingTypeIsNotFoundInModel() { // Arrange _model.Model.SetAnnotationValue <ClrTypeAnnotation>(_model.Order, value: null); var customer = Expression.Constant(new Customer()); var ordersProperty = _model.Customer.NavigationProperties().Single(p => p.Name == "Orders"); var parser = new ODataQueryOptionParser( _model.Model, _model.Order, _model.Orders, new Dictionary <string, string> { { "$filter", "ID eq 1" } }); var filterCaluse = parser.ParseFilter(); // Act & Assert ExceptionAssert.Throws <ODataException>( () => _binder.CreatePropertyValueExpressionWithFilter(_model.Customer, ordersProperty, customer, filterCaluse), "The provided mapping does not contain a resource for the resource type 'NS.Order'."); // NetFx and NetCore differ in the way Expression is converted to a string. //Assert.Equal(ExpressionType.Convert, property.NodeType); //var unaryExpression = (property as UnaryExpression); //Assert.NotNull(unaryExpression); //Assert.Equal(String.Format("{0}.ID", customer.ToString()), unaryExpression.Operand.ToString()); //Assert.Equal(typeof(int?), unaryExpression.Type); }
public static FilterClause GetFilterClause <T>(IDictionary <string, string> queryOptions, IServiceProvider serviceProvider, bool useFilterOption = false) where T : class { IEdmModel model = GetModel <T>(serviceProvider); IEdmEntityType productType = model.SchemaElements.OfType <IEdmEntityType>().Single(t => t.Name == typeof(T).Name); IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet(typeof(T).Name); ODataQueryOptionParser parser = new ODataQueryOptionParser ( model, productType, entitySet, queryOptions ); if (useFilterOption) { return(GetFilterClauseFromFilterOption ( model, entitySet, parser, queryOptions["$filter"] )); } return(parser.ParseFilter()); }
public void EmptyQueryOptionDictionaryShouldWork() { var uriParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet(), new Dictionary <string, string>()); uriParser.ParseFilter().Should().BeNull(); uriParser.ParseSelectAndExpand().Should().BeNull(); uriParser.ParseOrderBy().Should().BeNull(); uriParser.ParseTop().Should().Be(null); uriParser.ParseSkip().Should().Be(null); uriParser.ParseCount().Should().Be(null); uriParser.ParseSearch().Should().BeNull(); }
private QueryNode TranslateFilterExpression(string filter) { var parser = new ODataQueryOptionParser(_model, _customerEntityType, _customersEntitySet, new Dictionary <string, string> { { "$filter", filter } }); FilterClause filterClause = parser.ParseFilter(); var translator = new ParameterAliasNodeTranslator( new Dictionary <string, SingleValueNode> { { "@p", _parameterAliasMappedNode } }); QueryNode translatedNode = filterClause.Expression.Accept(translator); return(translatedNode); }
private static QueryClause CreateQueryClause(string query, IEdmModel model, Type type) { IEdmEntityType entityType = model.SchemaElements.OfType <IEdmEntityType>().Single(t => t.Name == type.Name); Assert.NotNull(entityType); // Guard IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers"); Assert.NotNull(entitySet); // Guard string[] queryItems = query.Split('&'); Dictionary <string, string> queries = new Dictionary <string, string>(); foreach (string item in queryItems) { if (item.StartsWith("$select=", StringComparison.Ordinal)) { queries["$select"] = item.Substring(8); } else if (item.StartsWith("$expand=", StringComparison.Ordinal)) { queries["$expand"] = item.Substring(8); } else if (item.StartsWith("$filter=", StringComparison.Ordinal)) { queries["$filter"] = item.Substring(8); } else if (item.StartsWith("$orderby=", StringComparison.Ordinal)) { queries["$orderby"] = item.Substring(9); } else if (item.StartsWith("$compute=", StringComparison.Ordinal)) { queries["$compute"] = item.Substring(9); } } ODataQueryOptionParser parser = new ODataQueryOptionParser(model, entityType, entitySet, queries); return(new QueryClause { Filter = parser.ParseFilter(), OrderBy = parser.ParseOrderBy(), SelectExpand = parser.ParseSelectAndExpand(), Compute = parser.ParseCompute() }); }
private static FilterClause CreateFilterClause(string filter, IEdmModel model, Type type) { IEdmEntityType entityType = model.SchemaElements.OfType <IEdmEntityType>().Single(t => t.Name == type.Name); Assert.NotNull(entityType); // Guard IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Products"); Assert.NotNull(entitySet); // Guard ODataQueryOptionParser parser = new ODataQueryOptionParser(model, entityType, entitySet, new Dictionary <string, string> { { "$filter", filter } }); return(parser.ParseFilter()); }
public void CreatePropertyValueExpressionWithFilter_Collection_Works_HandleNullPropagationOptionIsTrue() { // Arrange _model.Model.SetAnnotationValue(_model.Order, new ClrTypeAnnotation(typeof(Order))); _settings.HandleNullPropagation = HandleNullPropagationOption.True; var customer = Expression.Constant(new Customer { Orders = new[] { new Order { ID = 1 }, new Order { ID = 2 } } }); var ordersProperty = _model.Customer.NavigationProperties().Single(p => p.Name == "Orders"); var parser = new ODataQueryOptionParser( _model.Model, _model.Order, _model.Orders, new Dictionary <string, string> { { "$filter", "ID eq 1" } }); var filterCaluse = parser.ParseFilter(); // Act var filterInExpand = _binder.CreatePropertyValueExpressionWithFilter( _model.Customer, ordersProperty, customer, filterCaluse); // Assert Assert.Equal( string.Format( "IIF((value({0}) == null), null, IIF((value({0}).Orders == null), null, " + "value({0}).Orders.AsQueryable().Where($it => ($it.ID == value({1}).TypedProperty))))", customer.Type, "Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Int32]"), filterInExpand.ToString()); var orders = Expression.Lambda(filterInExpand).Compile().DynamicInvoke() as IEnumerable <Order>; Assert.Single(orders); Assert.Equal(1, orders.ToList()[0].ID); }
private FilterClause CreateFilterClause(string filterExpression) { const string uriBase = "http://service/"; Uri uri = new Uri(uriBase + "Pet1Set?$filter=" + filterExpression); ODataUriParser parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri(uriBase), uri); IEdmEntitySet entitySet = HardCodedTestModel.GetPet1Set(); Dictionary <string, string> queryOptions = new Dictionary <string, string>() { { "$filter", filterExpression } }; // Use query option parser to help create the filter because it takes care of a bunch of instantiations ODataQueryOptionParser queryOptionParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, entitySet.EntityType(), entitySet, queryOptions); return(queryOptionParser.ParseFilter()); }
public void CreatePropertyValueExpressionWithFilter_ThrowsODataException_IfMappingTypeIsNotFoundInModel() { // Arrange _model.Model.SetAnnotationValue <ClrTypeAnnotation>(_model.Order, value: null); var customer = Expression.Constant(new Customer()); var ordersProperty = _model.Customer.NavigationProperties().Single(p => p.Name == "Orders"); var parser = new ODataQueryOptionParser( _model.Model, _model.Order, _model.Orders, new Dictionary <string, string> { { "$filter", "ID eq 1" } }); var filterCaluse = parser.ParseFilter(); // Act & Assert Assert.Throws <ODataException>( () => _binder.CreatePropertyValueExpressionWithFilter(_model.Customer, ordersProperty, customer, filterCaluse), "The provided mapping does not contain an entry for the entity type 'NS.Order'."); }
public void CreatePropertyValueExpressionWithFilter_Single_Works_HandleNullPropagationOptionIsTrue() { // Arrange _settings.HandleReferenceNavigationPropertyExpandFilter = true; _settings.HandleNullPropagation = HandleNullPropagationOption.True; var order = Expression.Constant( new Order { Customer = new Customer { ID = 1 } } ); var customerProperty = _model.Order.NavigationProperties().Single(p => p.Name == "Customer"); var parser = new ODataQueryOptionParser( _model.Model, _model.Customer, _model.Customers, new Dictionary <string, string> { { "$filter", "ID ne 1" } }); var filterCaluse = parser.ParseFilter(); // Act var filterInExpand = _binder.CreatePropertyValueExpressionWithFilter(_model.Order, customerProperty, order, filterCaluse); // Assert Assert.Equal( string.Format( "IIF((value({0}) == null), null, IIF((value({0}).Customer == null), null, " + "IIF((value({0}).Customer.ID != value(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Int32]).TypedProperty), " + "value({0}).Customer, null)))", order.Type), filterInExpand.ToString()); var customer = Expression.Lambda(filterInExpand).Compile().DynamicInvoke() as Customer; Assert.Null(customer); }
/// <summary> /// Apply $filter parameter to query. /// </summary> /// <param name="query"> /// The OData aware query. /// </param> /// <param name="filterText"> /// The $filter parameter text. /// </param> /// <param name="entitySetName"> /// The entity set name. /// </param> /// <typeparam name="T"> /// The query type param /// </typeparam> /// <returns> /// The <see cref="ODataQuery{T}"/> query with applied filter parameter. /// </returns> /// <exception cref="ArgumentNullException"> /// Argument Null Exception /// </exception> public static ODataQuery <T> Filter <T>(this ODataQuery <T> query, string filterText, string entitySetName = null) { if (query == null) { throw new ArgumentNullException(nameof(query)); } if (filterText == null) { throw new ArgumentNullException(nameof(filterText)); } IEdmModel edmModel = query.EdmModel; ODataQueryOptionParser queryOptionParser = GetParser( query, entitySetName, new Dictionary <string, string> { { "$filter", filterText } }); ODataSettings settings = query.ServiceProvider.GetRequiredService <ODataSettings>(); FilterClause filterClause = queryOptionParser.ParseFilter(); SingleValueNode filterExpression = filterClause.Expression.Accept( new ParameterAliasNodeTranslator(queryOptionParser.ParameterAliasNodes)) as SingleValueNode; filterExpression = filterExpression ?? new ConstantNode(null); filterClause = new FilterClause(filterExpression, filterClause.RangeVariable); Contract.Assert(filterClause != null); var validator = new FilterQueryValidator(settings.DefaultQuerySettings); validator.Validate(filterClause, settings.ValidationSettings, edmModel); Expression filter = FilterBinder.Bind(query, filterClause, typeof(T), query.ServiceProvider); var result = ExpressionHelpers.Where(query, filter, typeof(T)); return(new ODataQuery <T>(result, query.ServiceProvider)); }
public QueryDescription <T> Parse <T>() { var model = GetCachedEdmModel(typeof(T)); var entities = model.FindDeclaredNavigationSource("Entities"); var parser = new ODataQueryOptionParser(model, entities.EntityType(), entities, Dictionary); var filter = Filter == null ? null : parser.ParseFilter(); var orderby = OrderBy == null ? null : parser.ParseOrderBy(); var search = Search == null ? null : parser.ParseSearch(); var apply = Apply == null ? null : parser.ParseApply(); var result = new QueryDescription <T>() { Skip = Skip == null ? 0 : parser.ParseSkip() ?? 0, Take = Top == null ? null : parser.ParseTop(), Filter = ParseFilter(filter), Sorting = ParseOrderBy(orderby), Search = ParseSearch(search), Grouping = ParseApply(apply) }; if (result.Take == null) { result.Page = result.Skip == 0 ? 1 : 2; } else { result.Page = (result.Skip / result.Take.Value) + 1; if (result.Skip % result.Take.Value > 0) { result.Page++; } } return(result); }