/// <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="writeContext"/>. /// </summary> /// <param name="entityType">The entity type of the entry that would be written.</param> /// <param name="writeContext">The serializer context to be used while creating the collection.</param> /// <remarks>The default constructor is for unit testing only.</remarks> public SelectExpandNode(IEdmEntityType entityType, ODataSerializerContext writeContext) : this(writeContext.SelectExpandClause, entityType, writeContext.Model) { var queryOptionParser = new ODataQueryOptionParser( writeContext.Model, entityType, writeContext.NavigationSource, _extraQueryParameters); var selectExpandClause = queryOptionParser.ParseSelectAndExpand(); if (selectExpandClause != null) { 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 (!ExpandedNavigationProperties.ContainsKey(navigationProperty)) { ExpandedNavigationProperties.Add(navigationProperty, expandItem.SelectAndExpand); } } } } SelectedNavigationProperties.ExceptWith(ExpandedNavigationProperties.Keys); }
/// <summary> /// Initializes a new instance of the <see cref="ODataQueryOptions"/> class based on the incoming request and some metadata information from /// the <see cref="ODataQueryContext"/>. /// </summary> /// <param name="context">The <see cref="ODataQueryContext"/> which contains the <see cref="IEdmModel"/> and some type information.</param> /// <param name="request">The incoming request message.</param> public ODataQueryOptions(ODataQueryContext context, HttpRequest request) { if (context == null) { throw Error.ArgumentNull("context"); } if (request == null) { throw Error.ArgumentNull("request"); } _assemblyProvider = request.AssemblyProvider(); Context = context; Request = request; RawValues = new ODataRawQueryOptions(); var queryOptionDict = request.Query.ToDictionary(p => p.Key, p => p.Value.FirstOrDefault()); _queryOptionParser = new ODataQueryOptionParser( context.Model, context.ElementType, context.NavigationSource, queryOptionDict); BuildQueryOptions(queryOptionDict); }
/// <summary> /// Initializes a new instance of the <see cref="SelectExpandQueryOption"/> class. /// </summary> /// <param name="select">The $select query parameter value.</param> /// <param name="expand">The $expand query parameter value.</param> /// <param name="context">The <see cref="ODataQueryContext"/> which contains the <see cref="IEdmModel"/> and some type information.</param> /// <param name="queryOptionParser">The <see cref="ODataQueryOptionParser"/> which is used to parse the query option.</param> public SelectExpandQueryOption(string select, string expand, ODataQueryContext context, ODataQueryOptionParser queryOptionParser) { if (context == null) { throw Error.ArgumentNull("context"); } if (String.IsNullOrEmpty(select) && String.IsNullOrEmpty(expand)) { throw Error.Argument(SRResources.SelectExpandEmptyOrNull); } if (queryOptionParser == null) { throw Error.ArgumentNull("queryOptionParser"); } IEdmEntityType entityType = context.ElementType as IEdmEntityType; if (entityType == null) { throw Error.Argument("context", SRResources.SelectNonEntity, context.ElementType.ToTraceString()); } Context = context; RawSelect = select; RawExpand = expand; Validator = new SelectExpandQueryValidator(); _queryOptionParser = queryOptionParser; }
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 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(); }
/// <summary> /// Initialize a UriParser. We have to initialize UriParser seperately for parsing path, because we may set BatchReferenceCallback before ParsePath. /// </summary> private void Initialize() { if (this.odataPath != null) { return; } this.ParameterAliasValueAccessor = new ParameterAliasValueAccessor(queryOptions.GetParameterAliases()); this.odataPath = this.ParsePathImplementation(); ODataPathSegment lastSegment = this.odataPath.LastSegment; ODataPathSegment previous = null; var segs = odataPath.GetEnumerator(); int count = 0; while (++count < odataPath.Count && segs.MoveNext()) { } previous = segs.Current; if (lastSegment != null) { // use previous segment if the last one is Key or Count Segment if (lastSegment is KeySegment || lastSegment is CountSegment) { lastSegment = previous; } this.targetNavigationSource = lastSegment.TargetEdmNavigationSource; this.targetEdmType = lastSegment.TargetEdmType; if (this.targetEdmType != null) { IEdmCollectionType collectionType = this.targetEdmType as IEdmCollectionType; if (collectionType != null) { this.targetEdmType = collectionType.ElementType.Definition; } } } InitQueryOptionDic(); this.queryOptionParser = new ODataQueryOptionParser(this.Model, this.targetEdmType, this.targetNavigationSource, queryOptionDic) { Configuration = this.configuration }; }
[InlineData("ID", "Orders($select=ID),Orders($expand=Customer($select=ID))", true, "ID")] // deep expand and selects public void GetPropertiesToBeSelected_Selects_ExpectedProperties_OnCustomer( string select, string expand, bool specialCustomer, string structuralPropertiesToSelect) { // Arrange ODataQueryOptionParser parser = new ODataQueryOptionParser(_model.Model, _model.Customer, _model.Customers, new Dictionary<string, string> { { "$select", select }, { "$expand", expand } }); SelectExpandClause selectExpandClause = parser.ParseSelectAndExpand(); IEdmEntityType entityType = specialCustomer ? _model.SpecialCustomer : _model.Customer; // Act SelectExpandNode selectExpandNode = new SelectExpandNode(selectExpandClause, entityType, _model.Model); var result = selectExpandNode.SelectedStructuralProperties; // Assert Assert.Equal(structuralPropertiesToSelect, String.Join(",", result.Select(p => p.Name).OrderBy(n => n))); }
private static void TestCaseInsensitive() { Console.WriteLine("TestCaseInsensitive"); var parser = new ODataUriParser( extModel.Model, ServiceRoot, new Uri("http://demo/odata.svc/People(1)/Pets/TestNS.Fish?$orderby=Color")); var path = parser.ParsePath(); var clause = parser.ParseOrderBy(); Console.WriteLine(path.ToLogString()); Console.WriteLine(clause.Expression.ToLogString()); var parser2 = new ODataUriParser( extModel.Model, ServiceRoot, new Uri("http://demo/odata.svc/people(1)/pets/testns.fish?$ORDERBY=color")) { Resolver = new ODataUriResolver { EnableCaseInsensitive = true } }; // Identical to path and clause var path2 = parser2.ParsePath(); var clause2 = parser2.ParseOrderBy(); Console.WriteLine(path2.ToLogString()); Console.WriteLine(clause2.Expression.ToLogString()); // Query option parser also supports custom resolver var parser3 = new ODataQueryOptionParser( extModel.Model, extModel.Fish, extModel.PetSet, new Dictionary<string, string> { {"$orderby", "color"} }) { Resolver = new ODataUriResolver { EnableCaseInsensitive = true } }; var clause3 = parser3.ParseOrderBy(); Console.WriteLine(clause3.Expression.ToLogString()); }
// This constructor is intended for unit testing only. internal CountQueryOption(string rawValue, ODataQueryContext context) { if (String.IsNullOrEmpty(rawValue)) { throw Error.ArgumentNullOrEmpty("rawValue"); } if (context == null) { throw Error.ArgumentNull("context"); } Context = context; RawValue = rawValue; _queryOptionParser = new ODataQueryOptionParser( context.Model, context.ElementType, context.NavigationSource, new Dictionary<string, string> { { "$count", rawValue } }); }
/// <summary> /// Initialize a new instance of <see cref="FilterQueryOption"/> based on the raw $filter value and /// an EdmModel from <see cref="ODataQueryContext"/>. /// </summary> /// <param name="rawValue">The raw value for $filter query. It can be null or empty.</param> /// <param name="context">The <see cref="ODataQueryContext"/> which contains the <see cref="IEdmModel"/> and some type information</param> /// <param name="queryOptionParser">The <see cref="ODataQueryOptionParser"/> which is used to parse the query option.</param> public FilterQueryOption(string rawValue, ODataQueryContext context, ODataQueryOptionParser queryOptionParser) { if (context == null) { throw Error.ArgumentNull("context"); } if (String.IsNullOrEmpty(rawValue)) { throw Error.ArgumentNullOrEmpty("rawValue"); } if (queryOptionParser == null) { throw Error.ArgumentNull("queryOptionParser"); } Context = context; RawValue = rawValue; _queryOptionParser = queryOptionParser; }
public void WriterSettingsIntegrationTestWithSelect() { var setting = new ODataMessageWriterSettings(); var edmModel = new EdmModel(); var defaultContainer = new EdmEntityContainer("TestModel", "DefaultContainer"); edmModel.AddElement(defaultContainer); var cityType = new EdmEntityType("TestModel", "City"); var cityIdProperty = cityType.AddStructuralProperty("Id", EdmCoreModel.Instance.GetInt32(/*isNullable*/false)); cityType.AddKeys(cityIdProperty); cityType.AddStructuralProperty("Name", EdmCoreModel.Instance.GetString(/*isNullable*/false)); cityType.AddStructuralProperty("Size", EdmCoreModel.Instance.GetInt32(/*isNullable*/false)); edmModel.AddElement(cityType); var citySet = defaultContainer.AddEntitySet("Cities", cityType); var result = new ODataQueryOptionParser(edmModel, cityType, citySet, new Dictionary<string, string> { { "$expand", "" }, { "$select", "Id,*" } }).ParseSelectAndExpand(); setting.SetServiceDocumentUri(ServiceDocumentUri); setting.ODataUri = new ODataUri() { SelectAndExpand = result }; setting.MetadataDocumentUri.Should().Equals(ServiceDocumentUri + "/$metadata"); string select, expand; setting.SelectExpandClause.GetSelectExpandPaths(out select, out expand); select.Should().Be("*"); }
/// <summary> /// Initialize a new instance of <see cref="ApplyQueryOption"/> based on the raw $apply value and /// an EdmModel from <see cref="ODataQueryContext"/>. /// </summary> /// <param name="rawValue">The raw value for $filter query. It can be null or empty.</param> /// <param name="context">The <see cref="ODataQueryContext"/> which contains the <see cref="IEdmModel"/> and some type information</param> /// <param name="queryOptionParser">The <see cref="ODataQueryOptionParser"/> which is used to parse the query option.</param> public ApplyQueryOption(string rawValue, ODataQueryContext context, ODataQueryOptionParser queryOptionParser) { if (context == null) { throw Error.ArgumentNull("context"); } if (String.IsNullOrEmpty(rawValue)) { throw Error.ArgumentNullOrEmpty("rawValue"); } if (queryOptionParser == null) { throw Error.ArgumentNull("queryOptionParser"); } Context = context; RawValue = rawValue; // TODO: Implement and add validator //Validator = new FilterQueryValidator(); _queryOptionParser = queryOptionParser; ResultClrType = Context.ElementClrType; }
public void CanApplyOrderBy_WithNestedParameterAlias() { // Arrange var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel(); var parser = new ODataQueryOptionParser( model, model.FindType("System.Web.OData.Builder.TestModels.Customer"), model.FindDeclaredNavigationSource("Default.Container.Customers"), new Dictionary<string, string> { { "$orderby", "@p1" }, { "@p2", "Name" }, { "@p1", "@p2" } }); var orderByOption = new OrderByQueryOption("@p1", new ODataQueryContext(model, typeof(Customer)), parser); var customers = (new List<Customer>{ new Customer { CustomerId = 1, Name = "Andy" }, new Customer { CustomerId = 2, Name = "Aaron" }, new Customer { CustomerId = 3, Name = "Alex" } }).AsQueryable(); // Act var results = orderByOption.ApplyTo(customers).ToArray(); // Assert Assert.Equal(2, results[0].CustomerId); Assert.Equal(3, results[1].CustomerId); Assert.Equal(1, results[2].CustomerId); }
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}, {"$count" , null}, {"$search" , 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.ParseCount().Should().Be(null); uriParser.ParseSearch().Should().BeNull(); }
public void CopyConstructorShouldCopyODataUri() { var edmModel = new EdmModel(); var defaultContainer = new EdmEntityContainer("TestModel", "DefaultContainer"); edmModel.AddElement(defaultContainer); var cityType = new EdmEntityType("TestModel", "City"); var cityIdProperty = cityType.AddStructuralProperty("Id", EdmCoreModel.Instance.GetInt32(/*isNullable*/false)); cityType.AddKeys(cityIdProperty); cityType.AddStructuralProperty("Name", EdmCoreModel.Instance.GetString(/*isNullable*/false)); cityType.AddStructuralProperty("Size", EdmCoreModel.Instance.GetInt32(/*isNullable*/false)); edmModel.AddElement(cityType); var citySet = defaultContainer.AddEntitySet("Cities", cityType); var result = new ODataQueryOptionParser(edmModel, cityType, citySet, new Dictionary<string, string> { { "$expand", "" }, { "$select", "Id,*" } }).ParseSelectAndExpand(); this.settings.ODataUri = new ODataUri() { ServiceRoot = new Uri("http://test.org"), SelectAndExpand = result, Path = new ODataUriParser(edmModel, new Uri("http://test.org"), new Uri("http://test.org/Cities(1)/Name")).ParsePath() }; var newSetting = new ODataMessageWriterSettings(this.settings); newSetting.MetadataDocumentUri.Should().Be(new Uri("http://test.org/$metadata")); newSetting.ODataUri.Path.ToResourcePathString(ODataUrlConventions.Default).Should().Be("Cities(1)/Name"); newSetting.IsIndividualProperty.Should().BeTrue(); string select, expand; newSetting.SelectExpandClause.GetSelectExpandPaths(out select, out expand); select.Should().Be("*"); }
public void WriteContainedEntityInDeltaFeedWithSelectExpand() { this.TestInit(this.GetModel()); ODataDeltaFeed feed = new ODataDeltaFeed(); ODataEntry entry = new ODataEntry() { TypeName = "MyNS.Product", Properties = new[] { new ODataProperty {Name = "Id", Value = new ODataPrimitiveValue(1)}, new ODataProperty {Name = "Name", Value = new ODataPrimitiveValue("Car")}, }, }; ODataEntry containedEntry = new ODataEntry() { TypeName = "MyNS.ProductDetail", Properties = new[] { new ODataProperty {Name = "Id", Value = new ODataPrimitiveValue(1)}, new ODataProperty {Name = "Detail", Value = new ODataPrimitiveValue("made in china")}, }, }; containedEntry.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceEntityTypeName = "MyNS.ProductDetail", NavigationSourceName = "Products(1)/Details", NavigationSourceKind = EdmNavigationSourceKind.ContainedEntitySet }); var result = new ODataQueryOptionParser(this.GetModel(), this.GetProductType(), this.GetProducts(), new Dictionary<string, string> { { "$expand", "Details($select=Detail)" }, { "$select", "Name" } }).ParseSelectAndExpand(); ODataUri odataUri = new ODataUri() { ServiceRoot = new Uri("http://host/service"), SelectAndExpand = result }; var outputContext = CreateJsonLightOutputContext(this.stream, this.GetModel(), false, odataUri); ODataJsonLightDeltaWriter writer = new ODataJsonLightDeltaWriter(outputContext, this.GetProducts(), this.GetProductType()); writer.WriteStart(feed); writer.WriteStart(containedEntry); writer.WriteEnd(); writer.WriteStart(entry); writer.WriteEnd(); writer.WriteEnd(); writer.Flush(); this.TestPayload().Should().Be("{\"@odata.context\":\"http://host/service/$metadata#Products(Name,Details,Details(Detail))/$delta\",\"value\":[{\"@odata.context\":\"http://host/service/$metadata#Products(1)/Details/$entity\",\"Id\":1,\"Detail\":\"made in china\"},{\"Id\":1,\"Name\":\"Car\"}]}"); }
public void CanApplyOrderBy_WithParameterAlias() { // Arrange var model = new ODataModelBuilder().Add_Customer_EntityType_With_Address().Add_Address_ComplexType().GetServiceModel(); var parser = new ODataQueryOptionParser( model, model.FindType("System.Web.OData.Builder.TestModels.Customer"), model.FindDeclaredNavigationSource("Default.Container.Customers"), new Dictionary<string, string> { { "$orderby", "@q desc,@p asc" }, { "@q", "Address/HouseNumber" }, { "@p", "CustomerId" } }); var orderByOption = new OrderByQueryOption("@q desc,@p asc", new ODataQueryContext(model, typeof(Customer)), parser); var customers = (new List<Customer>{ new Customer { CustomerId = 1, Address = new Address{HouseNumber = 2}}, new Customer { CustomerId = 2, Address = new Address{HouseNumber = 1}}, new Customer { CustomerId = 3, Address = new Address{HouseNumber = 3}}, new Customer { CustomerId = 4, Address = new Address{HouseNumber = 2}}, new Customer { CustomerId = 5, Address = new Address{HouseNumber = 1}}, }).AsQueryable(); // Act var results = orderByOption.ApplyTo(customers).ToArray(); // Assert Assert.Equal(3, results[0].CustomerId); Assert.Equal(1, results[1].CustomerId); Assert.Equal(4, results[2].CustomerId); Assert.Equal(2, results[3].CustomerId); Assert.Equal(5, results[4].CustomerId); }
public void CreateCollection_From_OrderByNode_Succeeds() { // Arrange ODataConventionModelBuilder builder = ODataModelBuilderMocks.GetModelBuilderMock<ODataConventionModelBuilder>(); builder.EntitySet<SampleClass>("entityset"); IEdmModel model = builder.GetEdmModel(); IEdmEntityType sampleClassEntityType = model.SchemaElements.Single(t => t.Name == "SampleClass") as IEdmEntityType; Assert.NotNull(sampleClassEntityType); // Guard IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("entityset"); Assert.NotNull(entitySet); // Guard ODataQueryOptionParser parser = new ODataQueryOptionParser(model, sampleClassEntityType, entitySet, new Dictionary<string, string> { { "$orderby", "Property1 desc, Property2 asc" } }); OrderByClause orderbyNode = parser.ParseOrderBy(); // Act ICollection<OrderByNode> nodes = OrderByNode.CreateCollection(orderbyNode); // Assert Assert.False(nodes.OfType<OrderByItNode>().Any()); IEnumerable<OrderByPropertyNode> propertyNodes = nodes.OfType<OrderByPropertyNode>(); Assert.Equal(2, propertyNodes.Count()); Assert.Equal("Property1", propertyNodes.First().Property.Name); Assert.Equal(OrderByDirection.Descending, propertyNodes.First().Direction); Assert.ReferenceEquals("Property2", propertyNodes.Last().Property.Name); Assert.Equal(OrderByDirection.Ascending, nodes.Last().Direction); }
public void WriteObjectInline_ExpandsUsingInnerSerializerUsingRightContext_ExpandedNavigationProperties() { // Arrange IEdmEntityType customerType = _customerSet.EntityType(); IEdmNavigationProperty ordersProperty = customerType.NavigationProperties().Single(p => p.Name == "Orders"); ODataQueryOptionParser parser = new ODataQueryOptionParser(_model, customerType, _customerSet, new Dictionary<string, string> { { "$select", "Orders" }, { "$expand", "Orders" } }); SelectExpandClause selectExpandClause = parser.ParseSelectAndExpand(); SelectExpandNode selectExpandNode = new SelectExpandNode { ExpandedNavigationProperties = { { ordersProperty, selectExpandClause.SelectedItems.OfType<ExpandedNavigationSelectItem>().Single().SelectAndExpand } } }; Mock<ODataWriter> writer = new Mock<ODataWriter>(); Mock<ODataEdmTypeSerializer> innerSerializer = new Mock<ODataEdmTypeSerializer>(ODataPayloadKind.Entry); innerSerializer .Setup(s => s.WriteObjectInline(_customer.Orders, ordersProperty.Type, writer.Object, It.IsAny<ODataSerializerContext>())) .Callback((object o, IEdmTypeReference t, ODataWriter w, ODataSerializerContext context) => { Assert.Same(context.NavigationSource.Name, "Orders"); Assert.Same(context.SelectExpandClause, selectExpandNode.ExpandedNavigationProperties.Single().Value); }) .Verifiable(); Mock<ODataSerializerProvider> serializerProvider = new Mock<ODataSerializerProvider>(); serializerProvider.Setup(p => p.GetEdmTypeSerializer(ordersProperty.Type)) .Returns(innerSerializer.Object); Mock<ODataEntityTypeSerializer> serializer = new Mock<ODataEntityTypeSerializer>(serializerProvider.Object); serializer.Setup(s => s.CreateSelectExpandNode(It.IsAny<EntityInstanceContext>())).Returns(selectExpandNode); serializer.CallBase = true; _writeContext.SelectExpandClause = selectExpandClause; // Act serializer.Object.WriteObjectInline(_customer, _customerType, writer.Object, _writeContext); // Assert innerSerializer.Verify(); // check that the context is rolled back Assert.Same(_writeContext.NavigationSource.Name, "Customers"); Assert.Same(_writeContext.SelectExpandClause, selectExpandClause); }
public void WriteObjectInline_CanWriteExpandedNavigationProperty_DerivedExpandedCollectionValuedNavigationPropertyIsNull() { // Arrange IEdmEntityType specialCustomerType = (IEdmEntityType)_specialCustomerType.Definition; IEdmNavigationProperty specialOrdersProperty = specialCustomerType.NavigationProperties().Single(p => p.Name == "SpecialOrders"); Mock<IEdmEntityObject> customer = new Mock<IEdmEntityObject>(); object specialOrdersValue = null; customer.Setup(c => c.TryGetPropertyValue("SpecialOrders", out specialOrdersValue)).Returns(true); customer.Setup(c => c.GetEdmType()).Returns(_specialCustomerType); IEdmEntityType customerType = _customerSet.EntityType(); ODataQueryOptionParser parser = new ODataQueryOptionParser( _model, customerType, _customerSet, new Dictionary<string, string> { { "$select", "Default.SpecialCustomer/SpecialOrders" }, { "$expand", "Default.SpecialCustomer/SpecialOrders" } }); SelectExpandClause selectExpandClause = parser.ParseSelectAndExpand(); SelectExpandNode selectExpandNode = new SelectExpandNode(); selectExpandNode.ExpandedNavigationProperties[specialOrdersProperty] = selectExpandClause.SelectedItems.OfType<ExpandedNavigationSelectItem>().Single().SelectAndExpand; Mock<ODataWriter> writer = new Mock<ODataWriter>(); writer.Setup(w => w.WriteStart(It.IsAny<ODataFeed>())).Callback( (ODataFeed feed) => { Assert.Null(feed.Count); Assert.Null(feed.DeltaLink); Assert.Null(feed.Id); Assert.Empty(feed.InstanceAnnotations); Assert.Null(feed.NextPageLink); }).Verifiable(); Mock<ODataEdmTypeSerializer> ordersSerializer = new Mock<ODataEdmTypeSerializer>(ODataPayloadKind.Entry); Mock<ODataSerializerProvider> serializerProvider = new Mock<ODataSerializerProvider>(); serializerProvider.Setup(p => p.GetEdmTypeSerializer(specialOrdersProperty.Type)) .Returns(ordersSerializer.Object); Mock<ODataEntityTypeSerializer> serializer = new Mock<ODataEntityTypeSerializer>(serializerProvider.Object); serializer.Setup(s => s.CreateSelectExpandNode(It.IsAny<EntityInstanceContext>())).Returns(selectExpandNode); serializer.CallBase = true; // Act serializer.Object.WriteObjectInline(customer.Object, _customerType, writer.Object, _writeContext); // Assert writer.Verify(); }
// This constructor is intended for unit testing only. internal SelectExpandQueryOption(string select, string expand, ODataQueryContext context) { if (context == null) { throw Error.ArgumentNull("context"); } if (String.IsNullOrEmpty(select) && String.IsNullOrEmpty(expand)) { throw Error.Argument(SRResources.SelectExpandEmptyOrNull); } IEdmEntityType entityType = context.ElementType as IEdmEntityType; if (entityType == null) { throw Error.Argument("context", SRResources.SelectNonEntity, context.ElementType.ToTraceString()); } Context = context; RawSelect = select; RawExpand = expand; Validator = new SelectExpandQueryValidator(); _queryOptionParser = new ODataQueryOptionParser( context.Model, context.ElementType, context.NavigationSource, new Dictionary<string, string> { { "$select", select }, { "$expand", expand } }); }
private SearchClause RunSearchTest(string search) { ODataQueryOptionParser queryOptionParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, null, null, new Dictionary<string, string> { { "$search", search } }); return queryOptionParser.ParseSearch(); }
/// <summary> /// Initialize a UriParser. We have to initialize UriParser seperately for parsing path, because we may set BatchReferenceCallback before ParsePath. /// </summary> private void Initialize() { if (this.odataPath != null) { return; } // When parse path failed first time, the alias node would be not null, but already removed from query options, so do not set it in this case. if (this.ParameterAliasValueAccessor == null) { this.ParameterAliasValueAccessor = new ParameterAliasValueAccessor(queryOptions.GetParameterAliases()); } this.odataPath = this.ParsePathImplementation(); ODataPathSegment lastSegment = this.odataPath.LastSegment; ODataPathSegment previous = null; var segs = odataPath.GetEnumerator(); int count = 0; while (++count < odataPath.Count && segs.MoveNext()) { } previous = segs.Current; if (lastSegment != null) { // use previous segment if the last one is Key or Count Segment if (lastSegment is KeySegment || lastSegment is CountSegment) { lastSegment = previous; } this.targetNavigationSource = lastSegment.TargetEdmNavigationSource; this.targetEdmType = lastSegment.TargetEdmType; if (this.targetEdmType != null) { IEdmCollectionType collectionType = this.targetEdmType as IEdmCollectionType; if (collectionType != null) { this.targetEdmType = collectionType.ElementType.Definition; } } } InitQueryOptionDic(); this.queryOptionParser = new ODataQueryOptionParser(this.Model, this.targetEdmType, this.targetNavigationSource, queryOptionDic) { Configuration = this.configuration }; }
public void DefaultParameterAliasNodesShouldBeEmtpy() { var uriParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet(), new Dictionary<string, string>()); uriParser.ParameterAliasNodes.Count.Should().Be(0); }
public void WriteEntityInDeltaFeedWithSelectExpand() { this.TestInit(this.GetModel()); ODataDeltaFeed feed = new ODataDeltaFeed(); ODataEntry orderEntry= new ODataEntry() { Properties = new List<ODataProperty> { new ODataProperty { Name = "ShippingAddress", Value = new ODataComplexValue { Properties = new List<ODataProperty> { new ODataProperty { Name = "City", Value = "Shanghai" }, } } } }, SerializationInfo = new ODataFeedAndEntrySerializationInfo { NavigationSourceEntityTypeName = "Order", NavigationSourceKind = EdmNavigationSourceKind.EntitySet, NavigationSourceName = "Orders" }, }; var result = new ODataQueryOptionParser(this.GetModel(), this.GetCustomerType(), this.GetCustomers(), new Dictionary<string, string> { { "$expand", "Orders($select=ShippingAddress)" }, { "$select", "ContactName" } }).ParseSelectAndExpand(); ODataUri odataUri = new ODataUri() { ServiceRoot = new Uri("http://host/service"), SelectAndExpand = result }; var outputContext = CreateJsonLightOutputContext(this.stream, this.GetModel(), false, odataUri); ODataJsonLightDeltaWriter writer = new ODataJsonLightDeltaWriter(outputContext, this.GetProducts(), this.GetProductType()); writer.WriteStart(feed); writer.WriteStart(orderEntry); writer.WriteEnd(); writer.WriteEnd(); writer.Flush(); this.TestPayload().Should().Be("{\"@odata.context\":\"http://host/service/$metadata#Products(ContactName,Orders,Orders(ShippingAddress))/$delta\",\"value\":[{\"@odata.context\":\"http://host/service/$metadata#Orders/$entity\",\"ShippingAddress\":{\"City\":\"Shanghai\"}}]}"); }
private string GetWriterOutputForContentTypeAndKnobValue( string contentType, bool autoComputePayloadMetadataInJson, ODataItem[] itemsToWrite, EdmModel edmModel, IEdmEntitySetBase edmEntitySet, EdmEntityType edmEntityType, string selectClause = null, string expandClause = null, string resourcePath = null, bool enableFullValidation = true) { MemoryStream outputStream = new MemoryStream(); IODataResponseMessage message = new InMemoryMessage() { Stream = outputStream }; message.SetHeader("Content-Type", contentType); ODataMessageWriterSettings settings = new ODataMessageWriterSettings() { AutoComputePayloadMetadataInJson = autoComputePayloadMetadataInJson, EnableFullValidation = enableFullValidation }; var result = new ODataQueryOptionParser(edmModel, edmEntityType, edmEntitySet, new Dictionary<string, string> { { "$expand", expandClause }, { "$select", selectClause } }).ParseSelectAndExpand(); ODataUri odataUri = new ODataUri() { ServiceRoot = new Uri("http://example.org/odata.svc"), SelectAndExpand = result }; if (resourcePath != null) { Uri requestUri = new Uri("http://example.org/odata.svc/" + resourcePath); odataUri.RequestUri = requestUri; odataUri.Path = new ODataUriParser(edmModel, new Uri("http://example.org/odata.svc/"), requestUri).ParsePath(); } settings.ODataUri = odataUri; string output; using (var messageWriter = new ODataMessageWriter(message, settings, edmModel)) { int currentIdx = 0; if (itemsToWrite[currentIdx] is ODataFeed) { ODataWriter writer = messageWriter.CreateODataFeedWriter(edmEntitySet, edmEntityType); this.WriteFeed(writer, itemsToWrite, ref currentIdx); } else if (itemsToWrite[currentIdx] is ODataEntry) { ODataWriter writer = messageWriter.CreateODataEntryWriter(edmEntitySet, edmEntityType); this.WriteEntry(writer, itemsToWrite, ref currentIdx); } else { Assert.True(false, "Top level item to write must be entry or feed."); } currentIdx.Should().Be(itemsToWrite.Length, "Invalid list of items to write."); outputStream.Seek(0, SeekOrigin.Begin); output = new StreamReader(outputStream).ReadToEnd(); } return output; }
public void CreateCollection_PropertyAliased_IfEnabled(bool modelAliasing, string typeName, string propertyName) { // Arrange ODataConventionModelBuilder builder = new ODataConventionModelBuilder { ModelAliasingEnabled = modelAliasing }; builder.EntitySet<PropertyAlias>("entityset"); IEdmModel model = builder.GetEdmModel(); IEdmEntityType entityType = model.SchemaElements.Single(t => t.Name == typeName) as IEdmEntityType; Assert.NotNull(entityType); // Guard IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("entityset"); Assert.NotNull(entitySet); // Guard ODataQueryOptionParser parser = new ODataQueryOptionParser(model, entityType, entitySet, new Dictionary<string, string> { { "$orderby", propertyName + " desc, Id asc" } }); OrderByClause orderbyNode = parser.ParseOrderBy(); // Act ICollection<OrderByNode> nodes = OrderByNode.CreateCollection(orderbyNode); // Assert Assert.False(nodes.OfType<OrderByItNode>().Any()); IEnumerable<OrderByPropertyNode> propertyNodes = nodes.OfType<OrderByPropertyNode>(); Assert.Equal(2, propertyNodes.Count()); Assert.Equal(propertyName, propertyNodes.First().Property.Name); Assert.Equal(OrderByDirection.Descending, propertyNodes.First().Direction); Assert.ReferenceEquals("Id", propertyNodes.Last().Property.Name); Assert.Equal(OrderByDirection.Ascending, nodes.Last().Direction); }
public void WriteObjectInline_CanExpandNavigationProperty_ContainingEdmObject() { // Arrange IEdmEntityType customerType = _customerSet.EntityType(); IEdmNavigationProperty ordersProperty = customerType.NavigationProperties().Single(p => p.Name == "Orders"); Mock<IEdmObject> orders = new Mock<IEdmObject>(); orders.Setup(o => o.GetEdmType()).Returns(ordersProperty.Type); object ordersValue = orders.Object; Mock<IEdmEntityObject> customer = new Mock<IEdmEntityObject>(); customer.Setup(c => c.TryGetPropertyValue("Orders", out ordersValue)).Returns(true); customer.Setup(c => c.GetEdmType()).Returns(customerType.AsReference()); ODataQueryOptionParser parser = new ODataQueryOptionParser(_model, customerType, _customerSet, new Dictionary<string, string> { { "$select", "Orders" }, { "$expand", "Orders" } }); SelectExpandClause selectExpandClause = parser.ParseSelectAndExpand(); SelectExpandNode selectExpandNode = new SelectExpandNode(); selectExpandNode.ExpandedNavigationProperties[ordersProperty] = selectExpandClause.SelectedItems.OfType<ExpandedNavigationSelectItem>().Single().SelectAndExpand; Mock<ODataWriter> writer = new Mock<ODataWriter>(); Mock<ODataEdmTypeSerializer> ordersSerializer = new Mock<ODataEdmTypeSerializer>(ODataPayloadKind.Entry); ordersSerializer.Setup(s => s.WriteObjectInline(ordersValue, ordersProperty.Type, writer.Object, It.IsAny<ODataSerializerContext>())).Verifiable(); Mock<ODataSerializerProvider> serializerProvider = new Mock<ODataSerializerProvider>(); serializerProvider.Setup(p => p.GetEdmTypeSerializer(ordersProperty.Type)).Returns(ordersSerializer.Object); Mock<ODataEntityTypeSerializer> serializer = new Mock<ODataEntityTypeSerializer>(serializerProvider.Object); serializer.Setup(s => s.CreateSelectExpandNode(It.IsAny<EntityInstanceContext>())).Returns(selectExpandNode); serializer.CallBase = true; // Act serializer.Object.WriteObjectInline(customer.Object, _customerType, writer.Object, _writeContext); //Assert ordersSerializer.Verify(); }
public void CreateCollection_CopmplexType_Succeeds() { // Arrange CustomersModelWithInheritance model = new CustomersModelWithInheritance(); ODataQueryOptionParser parser = new ODataQueryOptionParser(model.Model, model.Customer, model.Customers, new Dictionary<string, string> { { "$orderby", "Address/Street desc, Address/City asc" } }); OrderByClause orderByNode = parser.ParseOrderBy(); // Act ICollection<OrderByNode> nodes = OrderByNode.CreateCollection(orderByNode); // Assert Assert.Equal(2, nodes.Count()); Assert.Equal("Street", (nodes.ToList()[0] as OrderByPropertyNode).Property.Name); Assert.Equal(OrderByDirection.Descending, nodes.ToList()[0].Direction); Assert.Equal("City", (nodes.ToList()[1] as OrderByPropertyNode).Property.Name); Assert.Equal(OrderByDirection.Ascending, nodes.ToList()[1].Direction); }
public void WriteObjectInline_CanWriteExpandedNavigationProperty_DerivedExpandedSingleValuedNavigationPropertyIsNull() { // Arrange IEdmEntityType specialOrderType = (IEdmEntityType)_specialOrderType.Definition; IEdmNavigationProperty customerProperty = specialOrderType.NavigationProperties().Single(p => p.Name == "SpecialCustomer"); Mock<IEdmEntityObject> order = new Mock<IEdmEntityObject>(); object customerValue = null; order.Setup(c => c.TryGetPropertyValue("SpecialCustomer", out customerValue)).Returns(true); order.Setup(c => c.GetEdmType()).Returns(_specialOrderType); IEdmEntityType orderType = (IEdmEntityType)_orderType.Definition; ODataQueryOptionParser parser = new ODataQueryOptionParser( _model, orderType, _orderSet, new Dictionary<string, string> { { "$select", "Default.SpecialOrder/SpecialCustomer" }, { "$expand", "Default.SpecialOrder/SpecialCustomer" } }); SelectExpandClause selectExpandClause = parser.ParseSelectAndExpand(); SelectExpandNode selectExpandNode = new SelectExpandNode(); selectExpandNode.ExpandedNavigationProperties[customerProperty] = selectExpandClause.SelectedItems.OfType<ExpandedNavigationSelectItem>().Single().SelectAndExpand; Mock<ODataWriter> writer = new Mock<ODataWriter>(); writer.Setup(w => w.WriteStart(null as ODataEntry)).Verifiable(); Mock<ODataEdmTypeSerializer> ordersSerializer = new Mock<ODataEdmTypeSerializer>(ODataPayloadKind.Entry); Mock<ODataSerializerProvider> serializerProvider = new Mock<ODataSerializerProvider>(); serializerProvider.Setup(p => p.GetEdmTypeSerializer(customerProperty.Type)) .Returns(ordersSerializer.Object); Mock<ODataEntityTypeSerializer> serializer = new Mock<ODataEntityTypeSerializer>(serializerProvider.Object); serializer.Setup(s => s.CreateSelectExpandNode(It.IsAny<EntityInstanceContext>())).Returns(selectExpandNode); serializer.CallBase = true; // Act serializer.Object.WriteObjectInline(order.Object, _orderType, writer.Object, _writeContext); // Assert writer.Verify(); }
public void ApplyWithParameterAlias_ReturnsCorrectQueryable(string filter, string parameterAliasValue, int[] parameterAliasModelIds) { // Arrange var model = GetParameterAliasModel(); var context = new ODataQueryContext(model, typeof(DataTypes)); IEdmType targetEdmType = model.FindType("System.Web.OData.Query.Expressions.DataTypes"); IEdmNavigationSource targetNavigationSource = model.FindDeclaredEntitySet("System.Web.OData.Query.Expressions.Products"); ODataQueryOptionParser parser = new ODataQueryOptionParser( model, targetEdmType, targetNavigationSource, new Dictionary<string, string> { { "$filter", filter }, { "@p", parameterAliasValue } }); var filterOption = new FilterQueryOption(filter, context, parser); IEnumerable<DataTypes> parameterAliasModels = ParameterAliasTestData; // Act IQueryable queryable = filterOption.ApplyTo(parameterAliasModels.AsQueryable(), new ODataQuerySettings { HandleNullPropagation = HandleNullPropagationOption.True }); // Assert Assert.NotNull(queryable); IEnumerable<DataTypes> actualResult = Assert.IsAssignableFrom<IEnumerable<DataTypes>>(queryable); Assert.Equal( parameterAliasModelIds, actualResult.Select(result => result.IntProp)); }