public void ParseNoDollarQueryOptionsShouldReturnNullIfNoDollarQueryOptionsIsNotEnabled()
        {
            var parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("People?filter=MyDog/Color eq 'Brown'&select=ID&expand=MyDog&orderby=ID&top=1&skip=2&count=true&search=FA&$unknown=&$unknownvalue&skiptoken=abc&deltatoken=def", UriKind.Relative));

            parser.ParseFilter().Should().BeNull();
            parser.ParseSelectAndExpand().Should().BeNull();
            parser.ParseOrderBy().Should().BeNull();
            parser.ParseTop().Should().Be(null);
            parser.ParseSkip().Should().Be(null);
            parser.ParseCount().Should().Be(null);
            parser.ParseSearch().Should().BeNull();
            parser.ParseSkipToken().Should().BeNull();
            parser.ParseDeltaToken().Should().BeNull();
        }
Beispiel #2
0
        public void ParseQueryOptionsShouldWork()
        {
            var parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("People?$filter=MyDog/Color eq 'Brown'&$select=ID&$expand=MyDog&$orderby=ID&$top=1&$skip=2&$count=true&$search=FA&$unknow=&$unknowvalue&$skiptoken=abc&$deltatoken=def", UriKind.Relative));

            parser.ParseSelectAndExpand().Should().NotBeNull();
            parser.ParseFilter().Should().NotBeNull();
            parser.ParseOrderBy().Should().NotBeNull();
            parser.ParseTop().Should().Be(1);
            parser.ParseSkip().Should().Be(2);
            parser.ParseCount().Should().Be(true);
            parser.ParseSearch().Should().NotBeNull();
            parser.ParseSkipToken().Should().Be("abc");
            parser.ParseDeltaToken().Should().Be("def");
        }
Beispiel #3
0
        public void ExpandPropertyDoesntExistShouldThrow()
        {
            ODataUriParser parser = this.CreateExpandUriParser(orderBase, "Potato");

            try
            {
                parser.ParseSelectAndExpand();
            }
            catch (ODataException e)
            {
                var expected = ODataExpectedExceptions.ODataException("MetadataBinder_PropertyNotDeclared", this.order.FullName(), "Potato");
                expected.ExpectedMessage.Verifier.VerifyMatch("MetadataBinder_PropertyNotDeclared", e.Message, this.order.FullName(), "Potato");
            }
        }
Beispiel #4
0
        public void ParseSelectExpandForContainment()
        {
            ODataUriParser parser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri("http://host/People?$select=MyContainedDog&$expand=MyContainedDog"))
            {
                Settings = { SelectExpandLimit = 5 }
            };
            SelectExpandClause       containedSelectExpandClause = parser.ParseSelectAndExpand();
            IEnumerator <SelectItem> enumerator = containedSelectExpandClause.SelectedItems.GetEnumerator();

            enumerator.MoveNext();
            ExpandedNavigationSelectItem expandedNavigationSelectItem = enumerator.Current as ExpandedNavigationSelectItem;

            expandedNavigationSelectItem.Should().NotBeNull();
            (expandedNavigationSelectItem.NavigationSource is IEdmContainedEntitySet).Should().BeTrue();
        }
        public void SelectQueryOption()
        {
            var            selectString = "$batch";
            ODataUriParser parser       = this.CreateSelectUriParser(bossBase, selectString);

            try
            {
                parser.ParseSelectAndExpand();
            }
            catch (ODataException e)
            {
                var expected = ODataExpectedExceptions.ODataException("UriSelectParser_SystemTokenInSelectExpand", "$batch", "$batch");
                expected.ExpectedMessage.Verifier.VerifyMatch("UriSelectParser_SystemTokenInSelectExpand", e.Message, "$batch", "$batch");
            }
        }
        public void SelectDoesNotExist()
        {
            var            selectString = "SpaghettiSquash";
            ODataUriParser parser       = this.CreateSelectUriParser(bossBase, selectString);

            try
            {
                parser.ParseSelectAndExpand();
            }
            catch (ODataException e)
            {
                var expected = ODataExpectedExceptions.ODataException("MetadataBinder_PropertyNotDeclared", this.employee.FullName(), "SpaghettiSquash");
                expected.ExpectedMessage.Verifier.VerifyMatch("MetadataBinder_PropertyNotDeclared", e.Message, this.employee.FullName(), "SpaghettiSquash");
            }
        }
        public void SpatialLengthPolygonNotFormedCorrectly()
        {
            ODataUriParser parser = this.CreateExpandUriParser(orderBase, "LoggedInEmployee($orderby=geo.length(geometry'Polygon(10 30, 7 28, 6 6, 10 30)') lt 0.5)");

            try
            {
                parser.ParseSelectAndExpand();
                Assert.Fail("Should throw with ODataException");
            }
            catch (ODataException e)
            {
                var expected = ODataExpectedExceptions.ODataException("UriQueryExpressionParser_UnrecognizedLiteralWithReason", "Edm.Geometry", "geometry'Polygon(10 30, 7 28, 6 6, 10 30)'", "11", "geo.length(geometry'Polygon(10 30, 7 28, 6 6, 10 30)') lt 0.5", "Expecting token type \"LeftParen\" with text \"\" but found \"Type:[2] Text:[10]\".");
                expected.ExpectedMessage.Verifier.VerifyMatch("UriQueryExpressionParser_UnrecognizedLiteralWithReason", e.Message, "Edm.Geometry", "geometry'Polygon(10 30, 7 28, 6 6, 10 30)'", "11", "geo.length(geometry'Polygon(10 30, 7 28, 6 6, 10 30)') lt 0.5", "Expecting token type \"LeftParen\" with text \"\" but found \"Type:[2] Text:[10]\".");
            }
        }
        public void ParseQueryOptionsShouldWork(string relativeUriString, bool enableNoDollarQueryOptions)
        {
            var parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri(relativeUriString, UriKind.Relative));

            parser.EnableNoDollarQueryOptions = enableNoDollarQueryOptions;
            parser.ParseSelectAndExpand().Should().NotBeNull();
            parser.ParseFilter().Should().NotBeNull();
            parser.ParseOrderBy().Should().NotBeNull();
            parser.ParseTop().Should().Be(1);
            parser.ParseSkip().Should().Be(2);
            parser.ParseCount().Should().Be(true);
            parser.ParseSearch().Should().NotBeNull();
            parser.ParseSkipToken().Should().Be("abc");
            parser.ParseDeltaToken().Should().Be("def");
        }
        public void SpatialLengthNotLineString()
        {
            ODataUriParser parser = this.CreateExpandUriParser(orderBase, "LoggedInEmployee($orderby=geo.length(geometry'Polygon((10 30, 7 28, 6 6, 10 30))') lt 0.5)");

            try
            {
                parser.ParseSelectAndExpand();
                Assert.Fail("Should throw with ODataException");
            }
            catch (ODataException e)
            {
                var expected = ODataExpectedExceptions.ODataException("MetadataBinder_NoApplicableFunctionFound", "geo.length", "geo.length(Edm.GeometryLineString Nullable=true); geo.length(Edm.GeographyLineString Nullable=true)");
                expected.ExpectedMessage.Verifier.VerifyMatch("MetadataBinder_NoApplicableFunctionFound", e.Message, "geo.length", "geo.length(Edm.GeometryLineString Nullable=true); geo.length(Edm.GeographyLineString Nullable=true)");
            }
        }
        public void NoneQueryOptionShouldWork()
        {
            var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, FullUri);
            var path      = uriParser.ParsePath();

            path.Should().HaveCount(1);
            path.LastSegment.ShouldBeEntitySetSegment(HardCodedTestModel.GetPeopleSet());
            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 ParseSelectExpandForContainment(string fullUriString, bool enableNoDollarQueryOptions)
        {
            ODataUriParser parser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(fullUriString))
            {
                Settings = { SelectExpandLimit = 5 }
            };

            parser.EnableNoDollarQueryOptions = enableNoDollarQueryOptions;
            SelectExpandClause       containedSelectExpandClause = parser.ParseSelectAndExpand();
            IEnumerator <SelectItem> enumerator = containedSelectExpandClause.SelectedItems.GetEnumerator();

            enumerator.MoveNext();
            ExpandedNavigationSelectItem expandedNavigationSelectItem = enumerator.Current as ExpandedNavigationSelectItem;

            expandedNavigationSelectItem.Should().NotBeNull();
            (expandedNavigationSelectItem.NavigationSource is IEdmContainedEntitySet).Should().BeTrue();
        }
        protected override ODataMessageWriterSettings GetWriterSettings()
        {
            ODataMessageWriterSettings settings = new ODataMessageWriterSettings
            {
                BaseUri = this.ServiceRootUri
            };

            ODataUriParser uriParser = new ODataUriParser(this.DataSource.Model, ServiceConstants.ServiceBaseUri, originalUri);

            settings.ODataUri = new ODataUri()
            {
                RequestUri      = originalUri,
                ServiceRoot     = this.ServiceRootUri,
                Path            = uriParser.ParsePath(),
                SelectAndExpand = uriParser.ParseSelectAndExpand()
            };

            // TODO: howang read the encoding from request.
            settings.SetContentType(string.IsNullOrEmpty(this.QueryContext.FormatOption) ? this.RequestAcceptHeader : this.QueryContext.FormatOption, Encoding.UTF8.WebName);
            return(settings);
        }
Beispiel #13
0
        public void ParseComputeAsExpandQueryOption()
        {
            // Create model
            EdmModel         model         = new EdmModel();
            EdmEntityType    elementType   = model.AddEntityType("DevHarness", "Entity");
            EdmEntityType    targetType    = model.AddEntityType("DevHarness", "Navigation");
            EdmTypeReference typeReference = new EdmStringTypeReference(EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.String), false);

            targetType.AddProperty(new EdmStructuralProperty(targetType, "Prop1", typeReference));
            EdmNavigationPropertyInfo propertyInfo = new EdmNavigationPropertyInfo();

            propertyInfo.Name               = "Nav1";
            propertyInfo.Target             = targetType;
            propertyInfo.TargetMultiplicity = EdmMultiplicity.One;
            EdmProperty navigation = EdmNavigationProperty.CreateNavigationProperty(elementType, propertyInfo);

            elementType.AddProperty(navigation);

            EdmEntityContainer container = model.AddEntityContainer("Default", "Container");

            container.AddEntitySet("Entities", elementType);

            // Define queries and new up parser.
            Uri            root   = new Uri("http://host");
            Uri            url    = new Uri("http://host/Entities?$expand=Nav1($compute=cast(Prop1, 'Edm.String') as NavProperty1AsString)");
            ODataUriParser parser = new ODataUriParser(model, root, url);

            // parse and validate
            SelectExpandClause clause = parser.ParseSelectAndExpand();
            List <SelectItem>  items  = clause.SelectedItems.ToList();

            items.Count.Should().Be(1);
            ExpandedNavigationSelectItem expanded = items[0] as ExpandedNavigationSelectItem;
            List <ComputeExpression>     computes = expanded.ComputeOption.ComputedItems.ToList();

            computes.Count.Should().Be(1);
            computes[0].Alias.ShouldBeEquivalentTo("NavProperty1AsString");
            computes[0].Expression.ShouldBeSingleValueFunctionCallQueryNode();
            computes[0].Expression.TypeReference.ShouldBeEquivalentTo(typeReference);
        }
Beispiel #14
0
        /// <summary>
        /// Binds the expand paths from the requests $expand query option to the sets/types/properties from the metadata provider of the service.
        /// </summary>
        /// <param name="requestDescription">The request description.</param>
        /// <param name="dataService">The data service.</param>
        /// <param name="expandQueryOption">The value of the $expand query option.</param>
        /// <returns>The bound expand segments.</returns>
        internal static IList <IList <ExpandItem> > BindExpandSegments(RequestDescription requestDescription, IDataService dataService, string expandQueryOption)
        {
            Debug.Assert(requestDescription != null, "requestDescription != null");
            Debug.Assert(dataService != null, "dataService != null");

            if (string.IsNullOrWhiteSpace(expandQueryOption))
            {
                return(new List <IList <ExpandItem> >());
            }

            ResourceType       targetResourceType = requestDescription.TargetResourceType;
            ResourceSetWrapper targetResourceSet  = requestDescription.TargetResourceSet;

            if (targetResourceType == null || targetResourceType.ResourceTypeKind != ResourceTypeKind.EntityType || targetResourceSet == null)
            {
                throw DataServiceException.CreateBadRequestError(Strings.RequestQueryProcessor_QueryExpandOptionNotApplicable);
            }

            MetadataProviderEdmModel model      = dataService.Provider.GetMetadataProviderEdmModel();
            IEdmEntityType           targetType = (IEdmEntityType)model.EnsureSchemaType(targetResourceType);
            IEdmEntitySet            targetSet  = model.EnsureEntitySet(targetResourceSet);

            SelectExpandClause clause;

            try
            {
                model.Mode = MetadataProviderEdmModelMode.SelectAndExpandParsing;
                clause     = ODataUriParser.ParseSelectAndExpand(/*select*/ null, expandQueryOption, model, targetType, targetSet);
            }
            catch (ODataException ex)
            {
                throw new DataServiceException(400, null, ex.Message, null, ex);
            }
            finally
            {
                model.Mode = MetadataProviderEdmModelMode.Serialization;
            }

            return(new ExpandAndSelectPathExtractor(clause).ExpandPaths);
        }
Beispiel #15
0
        public void ParseWithAllQueryOptionsWithoutAlias()
        {
            ODataUriParser parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("http://www.odata.com/OData/"), new Uri("http://www.odata.com/OData/Dogs?$select=Color, MyPeople&$expand=MyPeople&$filter=startswith(Color, 'Blue')&$orderby=Color asc"));

            parser.ParsePath().FirstSegment.ShouldBeEntitySetSegment(HardCodedTestModel.GetDogsSet());
            var myDogSelectedItems = parser.ParseSelectAndExpand().SelectedItems.ToList();

            myDogSelectedItems.Count.Should().Be(3);
            myDogSelectedItems[1].ShouldBePathSelectionItem(new ODataPath(new PropertySegment(HardCodedTestModel.GetDogColorProp())));
            var myPeopleExpansionSelectionItem = myDogSelectedItems[0].ShouldBeSelectedItemOfType <ExpandedNavigationSelectItem>().And;

            myPeopleExpansionSelectionItem.PathToNavigationProperty.Single().ShouldBeNavigationPropertySegment(HardCodedTestModel.GetDogMyPeopleNavProp());
            myPeopleExpansionSelectionItem.SelectAndExpand.SelectedItems.Should().BeEmpty();
            var startsWithArgs = parser.ParseFilter().Expression.ShouldBeSingleValueFunctionCallQueryNode("startswith").And.Parameters.ToList();

            startsWithArgs[0].ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetDogColorProp());
            startsWithArgs[1].ShouldBeConstantQueryNode("Blue");
            var orderby = parser.ParseOrderBy();

            orderby.Direction.Should().Be(OrderByDirection.Ascending);
            orderby.Expression.ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetDogColorProp());
        }
        public void EmptyValueQueryOptionShouldWork()
        {
            var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$filter=&$select=&$expand=&$orderby=&$top=&$skip=&$count=&$search=&$unknow=&$unknowvalue"));
            var path      = uriParser.ParsePath();

            path.Should().HaveCount(1);
            path.LastSegment.ShouldBeEntitySetSegment(HardCodedTestModel.GetPeopleSet());
            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, ""));
        }
Beispiel #17
0
        public void TryEnableNoDollarSignSystemQueryOption(string relativeUri)
        {
            // Create parser specifying optional-$-sign setting.
            var parser = new ODataUriParser(GetModel(), new Uri(relativeUri, UriKind.Relative))
            {
                EnableNoDollarQueryOptions = true
            };

            // Verify path is parsed correctly.
            Microsoft.OData.UriParser.ODataPath path = parser.ParsePath();
            Assert.NotNull(path);
            Assert.Equal(2, path.Count);

            // Verify expand & select clause is parsed correctly.
            SelectExpandClause result = parser.ParseSelectAndExpand();

            Assert.NotNull(result);
            Assert.Single(result.SelectedItems);
            ExpandedNavigationSelectItem selectItems = (result.SelectedItems.First() as ExpandedNavigationSelectItem);

            Assert.NotNull(selectItems);
            Assert.Equal("PermanentAccount", selectItems.NavigationSource.Name);
            Assert.Equal(2, selectItems.SelectAndExpand.SelectedItems.Count());
        }
Beispiel #18
0
        public void ParseComputeAsLevel2ExpandQueryOption()
        {
            // Create model
            EdmModel      model         = new EdmModel();
            EdmEntityType elementType   = model.AddEntityType("DevHarness", "Entity");
            EdmEntityType targetType    = model.AddEntityType("DevHarness", "Navigation");
            EdmEntityType subTargetType = model.AddEntityType("DevHarness", "SubNavigation");

            EdmTypeReference typeReference = new EdmStringTypeReference(EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.String), false);

            elementType.AddProperty(new EdmStructuralProperty(elementType, "Prop1", typeReference));
            targetType.AddProperty(new EdmStructuralProperty(targetType, "Prop1", typeReference));
            subTargetType.AddProperty(new EdmStructuralProperty(subTargetType, "Prop1", typeReference));

            EdmNavigationPropertyInfo propertyInfo = new EdmNavigationPropertyInfo();

            propertyInfo.Name               = "Nav1";
            propertyInfo.Target             = targetType;
            propertyInfo.TargetMultiplicity = EdmMultiplicity.One;
            EdmProperty navigation = EdmNavigationProperty.CreateNavigationProperty(elementType, propertyInfo);

            elementType.AddProperty(navigation);

            EdmNavigationPropertyInfo subPropertyInfo = new EdmNavigationPropertyInfo();

            subPropertyInfo.Name               = "SubNav1";
            subPropertyInfo.Target             = subTargetType;
            subPropertyInfo.TargetMultiplicity = EdmMultiplicity.One;
            EdmProperty subnavigation = EdmNavigationProperty.CreateNavigationProperty(targetType, subPropertyInfo);

            targetType.AddProperty(subnavigation);

            EdmEntityContainer container = model.AddEntityContainer("Default", "Container");

            container.AddEntitySet("Entities", elementType);

            // Define queries and new up parser.
            string address = "http://host/Entities?$compute=cast(Prop1, 'Edm.String') as Property1AsString, tolower(Prop1) as Property1Lower&" +
                             "$expand=Nav1($compute=cast(Prop1, 'Edm.String') as NavProperty1AsString;" +
                             "$expand=SubNav1($compute=cast(Prop1, 'Edm.String') as SubNavProperty1AsString))";
            Uri            root   = new Uri("http://host");
            Uri            url    = new Uri(address);
            ODataUriParser parser = new ODataUriParser(model, root, url);

            // parse
            ComputeClause      computeClause = parser.ParseCompute();
            SelectExpandClause selectClause  = parser.ParseSelectAndExpand();

            // validate top compute
            List <ComputeExpression> items = computeClause.ComputedItems.ToList();

            items.Count().Should().Be(2);
            items[0].Alias.ShouldBeEquivalentTo("Property1AsString");
            items[0].Expression.ShouldBeSingleValueFunctionCallQueryNode();
            items[0].Expression.TypeReference.ShouldBeEquivalentTo(typeReference);
            items[1].Alias.ShouldBeEquivalentTo("Property1Lower");
            items[1].Expression.ShouldBeSingleValueFunctionCallQueryNode();
            items[1].Expression.TypeReference.FullName().ShouldBeEquivalentTo("Edm.String");
            items[1].Expression.TypeReference.IsNullable.ShouldBeEquivalentTo(true); // tolower is built in function that allows nulls.

            // validate level 1 expand compute
            List <SelectItem> selectItems = selectClause.SelectedItems.ToList();

            selectItems.Count.Should().Be(1);
            ExpandedNavigationSelectItem expanded = selectItems[0] as ExpandedNavigationSelectItem;
            List <ComputeExpression>     computes = expanded.ComputeOption.ComputedItems.ToList();

            computes.Count.Should().Be(1);
            computes[0].Alias.ShouldBeEquivalentTo("NavProperty1AsString");
            computes[0].Expression.ShouldBeSingleValueFunctionCallQueryNode();
            computes[0].Expression.TypeReference.ShouldBeEquivalentTo(typeReference);

            // validate level 2 expand compute
            List <SelectItem> subSelectItems = expanded.SelectAndExpand.SelectedItems.ToList();

            subSelectItems.Count.Should().Be(1);
            ExpandedNavigationSelectItem subExpanded = subSelectItems[0] as ExpandedNavigationSelectItem;
            List <ComputeExpression>     subComputes = subExpanded.ComputeOption.ComputedItems.ToList();

            subComputes.Count.Should().Be(1);
            subComputes[0].Alias.ShouldBeEquivalentTo("SubNavProperty1AsString");
            subComputes[0].Expression.ShouldBeSingleValueFunctionCallQueryNode();
            subComputes[0].Expression.TypeReference.ShouldBeEquivalentTo(typeReference);
        }
Beispiel #19
0
        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);
            }
        }
Beispiel #20
0
        public ParseContext Parse(ODataUriParser parser, ParseContext sourceParseContext)
        {
            //Select implementation
            var targetParseContext            = new ParseContext();
            var targetQueryableSourceEntities = new List <Dictionary <string, object> >();
            var sourceEdmSetting = sourceParseContext.EdmEntityTypeSettings.FirstOrDefault();
            var targetEdmSetting = new EdmEntityTypeSettings()
            {
                RouteName  = SelectParser,
                Personas   = sourceEdmSetting.Personas,
                Properties = new List <EdmEntityTypePropertySetting>()
            };
            var selectExpandClause    = parser.ParseSelectAndExpand();
            var edmEntityType         = new EdmEntityType(EdmNamespaceName, SelectParser);
            var latestStateDictionary = new Dictionary <string, object>();

            //Construct the types. For now we support non-nested primitive types only. Everything else is an exception for now.
            var propertyList = new List <string>();

            foreach (var item in selectExpandClause.SelectedItems)
            {
                switch (item)
                {
                case PathSelectItem pathSelectItem:
                    IEnumerable <ODataPathSegment> segments = pathSelectItem.SelectedPath;
                    var firstPropertySegment = segments.FirstOrDefault();
                    if (firstPropertySegment != null)
                    {
                        var typeSetting = sourceEdmSetting.Properties.FirstOrDefault(predicate => predicate.PropertyName == firstPropertySegment.Identifier);

                        propertyList.Add(firstPropertySegment.Identifier);

                        if (typeSetting.GetEdmPrimitiveTypeKind() != EdmPrimitiveTypeKind.None)
                        {
                            var edmPrimitiveType = typeSetting.GetEdmPrimitiveTypeKind();
                            if (typeSetting.IsNullable.HasValue)
                            {
                                edmEntityType.AddStructuralProperty(firstPropertySegment.Identifier, edmPrimitiveType, typeSetting.IsNullable.Value);
                            }
                            else
                            {
                                edmEntityType.AddStructuralProperty(firstPropertySegment.Identifier, edmPrimitiveType);
                            }
                            targetEdmSetting.Properties.Add(new EdmEntityTypePropertySetting
                            {
                                PropertyName = typeSetting.PropertyName,
                                PropertyType = typeSetting.PropertyType,
                                IsNullable   = typeSetting.IsNullable
                            });
                        }
                        else
                        {
                            //We are doing $select on a property which is of type list. Which means
                            if (typeSetting.PropertyType == "List")
                            {
                                var edmComplexType = GetEdmComplexTypeReference(sourceParseContext);
                                edmEntityType.AddStructuralProperty(typeSetting.PropertyName, new EdmCollectionTypeReference(new EdmCollectionType(new EdmComplexTypeReference(edmComplexType, true))));
                                targetEdmSetting.Properties.Add(new EdmEntityTypePropertySetting
                                {
                                    PropertyName = typeSetting.PropertyName,
                                    PropertyType = typeSetting.PropertyType,
                                    IsNullable   = typeSetting.IsNullable
                                });
                            }
                            else
                            {
                                throw new FeatureNotSupportedException(SelectParser, $"Invalid Custom Selection-{typeSetting.PropertyName}-{typeSetting.PropertyType}");
                            }
                        }
                    }
                    else
                    {
                        throw new FeatureNotSupportedException(SelectParser, "Empty Path Segments");
                    }
                    break;

                case WildcardSelectItem wildcardSelectItem: throw new FeatureNotSupportedException(SelectParser, "WildcardSelect");

                case ExpandedNavigationSelectItem expandedNavigationSelectItem: throw new FeatureNotSupportedException(SelectParser, "ExpandedNavigation");

                case ExpandedReferenceSelectItem expandedReferenceSelectItem: throw new FeatureNotSupportedException(SelectParser, "ExpandedReference");

                case NamespaceQualifiedWildcardSelectItem namespaceQualifiedWildcardSelectItem: throw new FeatureNotSupportedException(SelectParser, "NamespaceQualifiedWildcard");
                }
            }

            //Register these dynamic types to model
            sourceParseContext.Model.AddElement(edmEntityType);
            ((EdmEntityContainer)sourceParseContext.Model.EntityContainer).AddEntitySet("Select", edmEntityType);


            //Construct the data
            var entityReferenceType         = new EdmEntityTypeReference(edmEntityType, true);
            var collectionRef               = new EdmCollectionTypeReference(new EdmCollectionType(entityReferenceType));
            var collection                  = new EdmEntityObjectCollection(collectionRef);
            var filteredQueryableEntityList = sourceParseContext.QueryableSourceEntities.Select(p => p.Where(p => propertyList.Contains(p.Key)));

            latestStateDictionary.Add(RequestFilterConstants.GetEntityTypeKeyName(SelectParser, StepIndex), entityReferenceType);

            foreach (var entity in filteredQueryableEntityList)
            {
                var entityDictionary = new Dictionary <string, object>();
                var obj = new EdmEntityObject(edmEntityType);
                foreach (var propertyKey in propertyList)
                {
                    var setting = targetEdmSetting.Properties.FirstOrDefault(predicate => predicate.PropertyName.Equals(propertyKey));
                    var data    = entity.FirstOrDefault(property => property.Key.Equals(propertyKey));

                    //This condition is when the type of selected property is a primitive type
                    if (setting.GetEdmPrimitiveTypeKind() != EdmPrimitiveTypeKind.None)
                    {
                        var propertyValue = !data.Equals(default(KeyValuePair <string, object>)) ? data.Value : null;
                        obj.TrySetPropertyValue(propertyKey, propertyValue);
                        entityDictionary.Add(propertyKey, propertyValue);
                    }
                    else
                    {
                        switch (setting.PropertyType)
                        {
                        case "List":
                            //TODO: There is scope for perf improvement
                            //We can re-use the previous constructed list instead of constructing one from scratch.
                            var subList        = (List <Dictionary <string, object> >)data.Value;
                            var subListContext = GetList(subList, GetEdmComplexTypeReference(sourceParseContext));
                            obj.TrySetPropertyValue(propertyKey, subListContext.Result);
                            entityDictionary.Add(propertyKey, subListContext.QueryAbleResult);
                            break;
                        }
                    }
                }
                collection.Add(obj);
                targetQueryableSourceEntities.Add(entityDictionary);
            }

            targetParseContext.Result = collection;
            targetParseContext.QueryableSourceEntities = targetQueryableSourceEntities;
            targetParseContext.Model = sourceParseContext.Model;
            targetParseContext.EdmEntityTypeSettings = new List <EdmEntityTypeSettings> {
                targetEdmSetting
            };
            targetParseContext.LatestStateDictionary = latestStateDictionary;
            return(targetParseContext);
        }