예제 #1
0
        internal IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings)
        {
            if (query == null)
            {
                throw Error.ArgumentNull("query");
            }
            if (querySettings == null)
            {
                throw Error.ArgumentNull("querySettings");
            }
            if (Context.ElementClrType == null)
            {
                throw Error.NotSupported(SRResources.ApplyToOnUntypedQueryOption, "ApplyTo");
            }

            ComputeClause computeClause = ComputeClause;

            Contract.Assert(computeClause != null);

            ODataQuerySettings updatedSettings = Context.UpdateQuerySettings(querySettings, query);

            var binder = new ComputeBinder(updatedSettings, _assembliesResolver, Context.ElementClrType, Context.Model, computeClause.ComputedItems);

            query = binder.Bind(query);

            return(query);
        }
예제 #2
0
 /// <summary>
 /// Create a new ODataUri. This contains the semantic meaning of the
 /// entire uri.
 /// </summary>
 /// <param name="parameterAliasValueAccessor">The ParameterAliasValueAccessor.</param>
 /// <param name="path">The top level path for this uri.</param>
 /// <param name="customQueryOptions">Any custom query options for this uri. Can be null.</param>
 /// <param name="selectAndExpand">Any $select or $expand option for this uri. Can be null.</param>
 /// <param name="filter">Any $filter option for this uri. Can be null.</param>
 /// <param name="orderby">Any $orderby option for this uri. Can be null</param>
 /// <param name="search">Any $search option for this uri. Can be null</param>
 /// <param name="apply">Any $apply option for this uri. Can be null</param>
 /// <param name="skip">Any $skip option for this uri. Can be null.</param>
 /// <param name="top">Any $top option for this uri. Can be null.</param>
 /// <param name="index">Any $index for this uri. Can be null.</param>
 /// <param name="queryCount">Any query $count option for this uri. Can be null.</param>
 /// <param name="compute">Any query $compute option for this uri. Can be null.</param>
 internal ODataUri(
     ParameterAliasValueAccessor parameterAliasValueAccessor,
     ODataPath path,
     IEnumerable <QueryNode> customQueryOptions,
     SelectExpandClause selectAndExpand,
     FilterClause filter,
     OrderByClause orderby,
     SearchClause search,
     ApplyClause apply,
     long?skip,
     long?top,
     long?index,
     bool?queryCount,
     ComputeClause compute = null)
 {
     this.ParameterAliasValueAccessor = parameterAliasValueAccessor;
     this.Path = path;
     this.CustomQueryOptions = new ReadOnlyCollection <QueryNode>(customQueryOptions.ToList());
     this.SelectAndExpand    = selectAndExpand;
     this.Filter             = filter;
     this.OrderBy            = orderby;
     this.Search             = search;
     this.Apply      = apply;
     this.Skip       = skip;
     this.Top        = top;
     this.Index      = index;
     this.QueryCount = queryCount;
     this.Compute    = compute;
 }
예제 #3
0
        /// <summary>Translates a <see cref="ComputeClause"/> into a string.</summary>
        /// <param name="computeClause">The compute clause to translate.</param>
        /// <returns>The translated String.</returns>
        internal string TranslateComputeClause(ComputeClause computeClause)
        {
            Debug.Assert(computeClause != null, "computeClause != null");

            bool          appendComma = false;
            StringBuilder sb          = new StringBuilder();

            foreach (var item in computeClause.ComputedItems)
            {
                if (appendComma)
                {
                    sb.Append(ExpressionConstants.SymbolComma);
                }
                else
                {
                    appendComma = true;
                }

                sb.Append(this.TranslateNode(item.Expression));
                sb.Append(ExpressionConstants.SymbolEscapedSpace); // "%20"
                sb.Append(ExpressionConstants.KeywordAs);
                sb.Append(ExpressionConstants.SymbolEscapedSpace); // "%20"
                sb.Append(item.Alias);
            }

            return(sb.ToString());
        }
예제 #4
0
 private void BuildCompute(ComputeClause computeClause)
 {
     foreach (ComputeExpression computeExpression in computeClause.ComputedItems)
     {
         Expression        expression       = _visitor.TranslateNode(computeExpression.Expression);
         IEdmTypeReference edmTypeReference = OeEdmClrHelper.GetEdmTypeReference(_visitor.EdmModel, expression.Type);
         _navigationItem.AddSelectItem(new OeSelectItem(new ComputeProperty(computeExpression.Alias, edmTypeReference, expression), false));
     }
 }
예제 #5
0
 private void BuildCompute(ComputeClause computeClause)
 {
     foreach (ComputeExpression computeExpression in computeClause.ComputedItems)
     {
         Expression        expression       = _visitor.TranslateNode(computeExpression.Expression);
         IEdmTypeReference edmTypeReference = OeEdmClrHelper.GetEdmTypeReference(_model, expression.Type);
         _selectItemInfos.Add(new SelectItemInfo(new ComputeProperty(computeExpression.Alias, edmTypeReference), expression));
     }
 }
예제 #6
0
        public void ComputeOptionSetCorrectly()
        {
            // Arrange & Act
            ComputeClause  compute = new ComputeClause(null);
            PathSelectItem select  = new PathSelectItem(new ODataSelectPath(), null, null, null, null, null, null, null, null, compute);

            // Assert
            Assert.NotNull(select.ComputeOption);
            Assert.Same(compute, select.ComputeOption);
        }
예제 #7
0
        /// <summary>
        /// Validates a <see cref="ComputeClause" />.
        /// </summary>
        /// <param name="computeClause">The <see cref="ComputeClause" />.</param>
        /// <param name="settings">The validation settings.</param>
        /// <param name="model">The EdmModel.</param>
        /// <remarks>
        /// Please note this method is not thread safe.
        /// </remarks>
        public virtual void Validate(ComputeClause computeClause, ODataValidationSettings settings, IEdmModel model)
        {
            CurrentAnyAllExpressionDepth = 0;
            CurrentNodeCount             = 0;
            base.Model = model;

            foreach (ComputeExpression computeITem in computeClause.ComputedItems)
            {
                ValidateQueryNode(computeITem.Expression, settings);
            }
        }
        internal void SetComputedProperties(ComputeClause computeClause)
        {
            if (computeClause == null || !computeClause.ComputedItems.Any())
            {
                return;
            }

            foreach (var item in computeClause.ComputedItems)
            {
                ComputedProperties.Add(item.Alias);
            }
        }
예제 #9
0
 private void ValidateComputeClause(ComputeClause compute, ODataUrlValidationContext validationContext)
 {
     if (compute != null)
     {
         ValidateItem(compute, validationContext);
         foreach (ComputeExpression computeExpression in compute.ComputedItems)
         {
             ValidateItem(computeExpression, validationContext);
             validationContext.ExpressionValidator.ValidateNode(computeExpression.Expression);
         }
     }
 }
예제 #10
0
 private void BuildCompute(ComputeClause computeClause)
 {
     if (computeClause != null)
     {
         foreach (ComputeExpression computeExpression in computeClause.ComputedItems)
         {
             Expression        expression       = _joinBuilder.Visitor.TranslateNode(computeExpression.Expression);
             IEdmTypeReference edmTypeReference = OeEdmClrHelper.GetEdmTypeReference(_edmModel, expression.Type);
             var computeProperty = new ComputeProperty(computeExpression.Alias, edmTypeReference, expression);
             _rootNavigationItem.AddStructuralItem(computeProperty, false);
         }
     }
 }
예제 #11
0
        private bool CompareCompute(ComputeClause clause1, ComputeClause clause2)
        {
            if (clause1 == clause2)
            {
                return(true);
            }
            if (clause1 == null || clause2 == null)
            {
                return(false);
            }

            return(EnumerableComparer.Compare(clause1.ComputedItems, clause2.ComputedItems, CompareComputeExpression));
        }
예제 #12
0
        public void CtorComputeQueryOption_GetQueryNodeParsesQuery()
        {
            // Arrange
            IEdmModel         model   = _model;
            ODataQueryContext context = new ODataQueryContext(model, typeof(ComputeCustomer))
            {
                RequestContainer = new MockServiceProvider()
            };

            // Act
            ComputeQueryOption compute       = new ComputeQueryOption("Price mul Qty as Total,Price mul 2.0 as Tax", context);
            ComputeClause      computeClause = compute.ComputeClause;

            // Assert
            Assert.Equal(2, computeClause.ComputedItems.Count());

            Assert.Collection(computeClause.ComputedItems,
                              e =>
            {
                Assert.Equal("Total", e.Alias);

                Assert.Equal(QueryNodeKind.BinaryOperator, e.Expression.Kind);
                BinaryOperatorNode binaryNode = e.Expression as BinaryOperatorNode;
                Assert.Equal(BinaryOperatorKind.Multiply, binaryNode.OperatorKind);
                Assert.Equal(QueryNodeKind.Convert, binaryNode.Right.Kind);
                ConvertNode convertNode = (ConvertNode)binaryNode.Right;
                Assert.Equal("Qty", ((SingleValuePropertyAccessNode)convertNode.Source).Property.Name);

                Assert.Equal(QueryNodeKind.SingleValuePropertyAccess, binaryNode.Left.Kind);
                var propertyAccessNode = binaryNode.Left as SingleValuePropertyAccessNode;
                Assert.Equal("Price", propertyAccessNode.Property.Name);
            },
                              e =>
            {
                Assert.Equal("Tax", e.Alias);

                Assert.Equal(QueryNodeKind.BinaryOperator, e.Expression.Kind);
                BinaryOperatorNode binaryNode = e.Expression as BinaryOperatorNode;
                Assert.Equal(BinaryOperatorKind.Multiply, binaryNode.OperatorKind);
                Assert.Equal(QueryNodeKind.Constant, binaryNode.Right.Kind);
                Assert.Equal(2.0, ((ConstantNode)binaryNode.Right).Value);

                Assert.Equal(QueryNodeKind.SingleValuePropertyAccess, binaryNode.Left.Kind);
                var propertyAccessNode = binaryNode.Left as SingleValuePropertyAccessNode;
                Assert.Equal("Price", propertyAccessNode.Property.Name);
            });
        }
예제 #13
0
        public ApplyClause BindApply(IEnumerable <QueryToken> tokens)
        {
            ExceptionUtils.CheckArgumentNotNull(tokens, "tokens");

            var transformations = new List <TransformationNode>();

            foreach (var token in tokens)
            {
                switch (token.Kind)
                {
                case QueryTokenKind.Aggregate:
                    AggregateTransformationNode aggregate = BindAggregateToken((AggregateToken)(token));
                    transformations.Add(aggregate);
                    aggregateExpressionsCache     = aggregate.Expressions;
                    state.AggregatedPropertyNames = aggregate.Expressions.Select(statement => statement.Alias).ToList();
                    break;

                case QueryTokenKind.AggregateGroupBy:
                    GroupByTransformationNode groupBy = BindGroupByToken((GroupByToken)(token));
                    transformations.Add(groupBy);
                    break;

                case QueryTokenKind.Compute:
                    ComputeClause             computeClause = this.computeBinder.BindCompute((ComputeToken)token);
                    ComputeTransformationNode computeNode   = new ComputeTransformationNode(computeClause);
                    transformations.Add(computeNode);
                    state.AggregatedPropertyNames = computeNode.ComputeClause.ComputedItems.Select(statement => statement.Alias).ToList();
                    break;

                default:
                    FilterClause             filterClause = this.filterBinder.BindFilter(token);
                    FilterTransformationNode filterNode   = new FilterTransformationNode(filterClause);
                    transformations.Add(filterNode);
                    break;
                }
            }

            return(new ApplyClause(transformations));
        }
예제 #14
0
        public void ParseComputeAsQueryOption()
        {
            // Create model
            EdmModel         model         = new EdmModel();
            EdmEntityType    elementType   = model.AddEntityType("DevHarness", "Entity");
            EdmTypeReference typeReference = new EdmStringTypeReference(EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.String), false);

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

            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?$compute=cast(Prop1, 'Edm.String') as Property1AsString, tolower(Prop1) as Property1Lower");
            ODataUriParser parser = new ODataUriParser(model, root, url);

            // parse and validate
            ComputeClause            clause = parser.ParseCompute();
            List <ComputeExpression> items  = clause.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.

            ComputeExpression copy = new ComputeExpression(items[0].Expression, items[0].Alias, null);

            copy.Expression.Should().NotBeNull();
            copy.TypeReference.Should().BeNull();
            ComputeClause varied = new ComputeClause(null);
        }
예제 #15
0
        public Expression Build(Expression source, OeQueryContext queryContext)
        {
            OrderByClause      orderBy         = queryContext.ODataUri.OrderBy;
            SelectExpandClause selectAndExpand = queryContext.ODataUri.SelectAndExpand;
            ComputeClause      compute         = queryContext.ODataUri.Compute;

            if (selectAndExpand != null)
            {
                BuildSelect(selectAndExpand, source, _visitor.Parameter, queryContext.MetadataLevel, queryContext.NavigationNextLink);
            }

            if (compute != null)
            {
                BuildCompute(compute);
            }

            if (orderBy != null)
            {
                BuildOrderBy(orderBy);
            }

            if (_selectItemInfos.Count == 0 && queryContext.SkipTokenParser != null)
            {
                queryContext.SkipTokenParser.Accessors = GetAccessors(source, orderBy);
                return(null);
            }

            var selectExpression = CreateSelectExpression(source, _visitor.Parameter);

            if (queryContext.SkipTokenParser != null)
            {
                queryContext.SkipTokenParser.Accessors = GetAccessors(selectExpression, orderBy);
            }

            return(selectExpression);
        }
예제 #16
0
 public override void Visit(ComputeClause node) { this.action(node); }
예제 #17
0
        /// <summary>
        /// Create a ComputeTransformationNode.
        /// </summary>
        /// <param name="ComputeClause">A <see cref="ComputeClause"/> representing the metadata bound Compute expression.</param>
        public ComputeTransformationNode(ComputeClause computeClause)
        {
            ExceptionUtils.CheckArgumentNotNull(computeClause, "computeClause");

            this.computeClause = computeClause;
        }
 public override void ExplicitVisit(ComputeClause fragment)
 {
     _fragments.Add(fragment);
 }
예제 #19
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);
        }