Пример #1
0
        /// <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);
        }
Пример #2
0
        /// <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();
 }
Пример #6
0
        /// <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
            };
        }
Пример #7
0
        [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)));
        }
Пример #8
0
        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());
        }
Пример #9
0
        // 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 } });
        }
Пример #10
0
        /// <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("*");
        }
Пример #12
0
        /// <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;
        }
Пример #13
0
        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\"}]}");
        }
Пример #17
0
        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 } });
        }
Пример #22
0
 private SearchClause RunSearchTest(string search)
 {
     ODataQueryOptionParser queryOptionParser = new ODataQueryOptionParser(HardCodedTestModel.TestModel, null, null, new Dictionary<string, string> { { "$search", search } });
     return queryOptionParser.ParseSearch();
 }
Пример #23
0
        /// <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\"}}]}");
        }
Пример #26
0
        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));
        }