/// <summary> /// Binds a LambdaToken to metadata. /// </summary> /// <param name="lambdaToken">Token to bind.</param> /// <param name="state">Object to hold the state of binding.</param> /// <returns>A metadata bound any or all node.</returns> internal LambdaNode BindLambdaToken(LambdaToken lambdaToken, BindingState state) { ExceptionUtils.CheckArgumentNotNull(lambdaToken, "LambdaToken"); ExceptionUtils.CheckArgumentNotNull(state, "state"); // Start by binding the parent token CollectionNode parent = this.BindParentToken(lambdaToken.Parent); RangeVariable rangeVariable = null; // Add the lambda variable to the stack if (lambdaToken.Parameter != null) { rangeVariable = NodeFactory.CreateParameterNode(lambdaToken.Parameter, parent); state.RangeVariables.Push(rangeVariable); } // Bind the expression SingleValueNode expression = this.BindExpressionToken(lambdaToken.Expression); // Create the node LambdaNode lambdaNode = NodeFactory.CreateLambdaNode(state, parent, expression, rangeVariable, lambdaToken.Kind); // Remove the lambda variable as it is now out of scope if (rangeVariable != null) { state.RangeVariables.Pop(); } return(lambdaNode); }
/// <summary> /// Creates an AnyNode or an AllNode from the given /// </summary> /// <param name="state">State of binding.</param> /// <param name="parent">Parent node to the lambda.</param> /// <param name="lambdaExpression">Bound Lambda expression.</param> /// <param name="newRangeVariable">The new range variable being added by this lambda node.</param> /// <param name="queryTokenKind">Token kind.</param> /// <returns>A new LambdaNode bound to metadata.</returns> internal static LambdaNode CreateLambdaNode( BindingState state, CollectionNode parent, SingleValueNode lambdaExpression, RangeVariable newRangeVariable, QueryTokenKind queryTokenKind) { LambdaNode lambdaNode; if (queryTokenKind == QueryTokenKind.Any) { lambdaNode = new AnyNode(new Collection <RangeVariable>(state.RangeVariables.ToList()), newRangeVariable) { Body = lambdaExpression, Source = parent, }; } else { Debug.Assert(queryTokenKind == QueryTokenKind.All, "LambdaQueryNodes must be Any or All only."); lambdaNode = new AllNode(new Collection <RangeVariable>(state.RangeVariables.ToList()), newRangeVariable) { Body = lambdaExpression, Source = parent, }; } return(lambdaNode); }
/// <summary> /// Creates a <see cref="FilterClause"/>. /// </summary> /// <param name="expression">The filter expression - this should evaluate to a single boolean value. Cannot be null.</param> /// <param name="rangeVariable">The parameter for the expression which represents a single value from the collection. Cannot be null.</param> /// <exception cref="System.ArgumentNullException">Throws if the input expression or rangeVariable is null.</exception> public FilterClause(SingleValueNode expression, RangeVariable rangeVariable) { ExceptionUtils.CheckArgumentNotNull(expression, "expression"); ExceptionUtils.CheckArgumentNotNull(rangeVariable, "parameter"); this.expression = expression; this.rangeVariable = rangeVariable; }
/// <summary> /// Creates an <see cref="OrderByClause"/>. /// </summary> /// <param name="thenBy">The next orderby to perform after performing this orderby, can be null in the case of only a single orderby expression.</param> /// <param name="expression">The order-by expression. Cannot be null.</param> /// <param name="direction">The direction to order.</param> /// <param name="rangeVariable">The rangeVariable for the expression which represents a single value from the collection we iterate over. </param> /// <exception cref="System.ArgumentNullException">Throws if the input expression or rangeVariable is null.</exception> public OrderByClause(OrderByClause thenBy, SingleValueNode expression, OrderByDirection direction, RangeVariable rangeVariable) { ExceptionUtils.CheckArgumentNotNull(expression, "expression"); ExceptionUtils.CheckArgumentNotNull(rangeVariable, "parameter"); this.thenBy = thenBy; this.expression = expression; this.direction = direction; this.rangeVariable = rangeVariable; }
/// <summary> /// Creates a RangeVariableReferenceNode for a given range variable /// </summary> /// <param name="rangeVariable">Name of the rangeVariable.</param> /// <returns>A new SingleValueNode (either a Resource or NonResource RangeVariableReferenceNode.</returns> internal static SingleValueNode CreateRangeVariableReferenceNode(RangeVariable rangeVariable) { if (rangeVariable.Kind == RangeVariableKind.NonResource) { return(new NonResourceRangeVariableReferenceNode(rangeVariable.Name, (NonResourceRangeVariable)rangeVariable)); } else { ResourceRangeVariable resourceRangeVariable = (ResourceRangeVariable)rangeVariable; return(new ResourceRangeVariableReferenceNode(resourceRangeVariable.Name, resourceRangeVariable)); } }
/// <summary> /// Binds a parameter token. /// </summary> /// <param name="rangeVariableToken">The parameter token to bind.</param> /// <param name="state">The state of metadata binding.</param> /// <returns>The bound query node.</returns> internal static SingleValueNode BindRangeVariableToken(RangeVariableToken rangeVariableToken, BindingState state) { ExceptionUtils.CheckArgumentNotNull(rangeVariableToken, "rangeVariableToken"); RangeVariable rangeVariable = state.RangeVariables.SingleOrDefault(p => p.Name == rangeVariableToken.Name); if (rangeVariable == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_ParameterNotInScope(rangeVariableToken.Name)); } return(NodeFactory.CreateRangeVariableReferenceNode(rangeVariable)); }
/// <summary> /// Determines the parent node. If the token has a parent, that token is bound. If not, then we /// use the implicit parameter from the BindingState as the parent node. /// </summary> /// <param name="segmentToken">Token to determine the parent node for.</param> /// <returns>A SingleValueQueryNode that is the parent node of the <paramref name="segmentToken"/>.</returns> private QueryNode DetermineParentNode(EndPathToken segmentToken) { ExceptionUtils.CheckArgumentNotNull(segmentToken, "segmentToken"); ExceptionUtils.CheckArgumentNotNull(state, "state"); if (segmentToken.NextToken != null) { return(this.bindMethod(segmentToken.NextToken)); } else { RangeVariable implicitRangeVariable = state.ImplicitRangeVariable; return(NodeFactory.CreateRangeVariableReferenceNode(implicitRangeVariable)); } }
private static BindingState CreateBindingState(ODataUriParserConfiguration config, IEdmNavigationSource resourcePathNavigationSource, IEdmNavigationSource targetNavigationSource, IEdmTypeReference elementType, HashSet <EndPathToken> generatedProperties = null, bool collapsed = false) { if (targetNavigationSource == null && elementType == null) { return(null); } // For example if we have https://url/Books?$expand=Authors($filter=Name eq $it/Name) // $filter=Name will reference Authors(the expanded entity). // $it/Name will reference Books(the resource identified by the path). // The BindingState ImplicitRangeVariable property will store the $it that references the expanded/selected item (The Implicit Range Variable). // We add to the Stack, the $it that references the resource identified by the path (The Explicit Range Variable). BindingState state = new BindingState(config) { ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType != null ? elementType : targetNavigationSource.EntityType().ToTypeReference(), targetNavigationSource) }; state.AggregatedPropertyNames = generatedProperties; state.IsCollapsed = collapsed; state.ResourcePathNavigationSource = resourcePathNavigationSource; if (resourcePathNavigationSource != null) { // This $it rangeVariable will be added the Stack. // We are adding a rangeVariable whose navigationSource is the resource path entity set. // ODATA spec: Example 106 http://docs.oasis-open.org/odata/odata/v4.01/csprd05/part2-url-conventions/odata-v4.01-csprd05-part2-url-conventions.html#sec_it RangeVariable explicitRangeVariable = NodeFactory.CreateImplicitRangeVariable( resourcePathNavigationSource.EntityType().ToTypeReference(), resourcePathNavigationSource); state.RangeVariables.Push(explicitRangeVariable); } // Create $this rangeVariable and add it to the Stack. RangeVariable dollarThisRangeVariable = NodeFactory.CreateDollarThisRangeVariable( elementType != null ? elementType : targetNavigationSource.EntityType().ToTypeReference(), targetNavigationSource); state.RangeVariables.Push(dollarThisRangeVariable); return(state); }
/// <summary> /// Build a segment representing $filter. /// </summary> /// <param name="expression">The filter expression - this should evaluate to a single boolean value.</param> /// <param name="rangeVariable">An expression that represents a single value from the collection.</param> /// <param name="navigationSource">The navigation source that this filter applies to.</param> /// <exception cref="System.ArgumentNullException">Throws if any input parameter is null.</exception> /// <remarks>$filter should not be applied on singletons or single entities.</remarks> public FilterSegment(SingleValueNode expression, RangeVariable rangeVariable, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(expression, "expression"); ExceptionUtils.CheckArgumentNotNull(rangeVariable, "rangeVariable"); ExceptionUtils.CheckArgumentNotNull(navigationSource, "navigationSource"); this.Identifier = UriQueryConstants.FilterSegment; this.SingleResult = false; this.TargetEdmNavigationSource = navigationSource; this.TargetKind = RequestTargetKind.Resource; this.TargetEdmType = rangeVariable.TypeReference.Definition; this.expression = expression; this.rangeVariable = rangeVariable; this.bindingType = navigationSource.Type; NodeToStringBuilder nodeToStringBuilder = new NodeToStringBuilder(); string expressionString = nodeToStringBuilder.TranslateNode(expression); this.literalText = UriQueryConstants.FilterSegment + ExpressionConstants.SymbolOpenParen + expressionString + ExpressionConstants.SymbolClosedParen; }
/// <summary> /// Create a AnyNode /// </summary> /// <param name="parameters">The name of the parameter list.</param> /// <param name="currentRangeVariable">The name of the new range variable being added by this AnyNode</param> public AnyNode(Collection <RangeVariable> parameters, RangeVariable currentRangeVariable) : base(parameters, currentRangeVariable) { }
/// <summary> /// Create an AllNode /// </summary> /// <param name="rangeVariables">The name of the rangeVariables list.</param> /// <param name="currentRangeVariable">The new range variable being added by this all node</param> public AllNode(Collection <RangeVariable> rangeVariables, RangeVariable currentRangeVariable) : base(rangeVariables, currentRangeVariable) { }
/// <summary> /// Create a LambdaNode /// </summary> /// <param name="rangeVariables">The collection of rangeVariables in scope for this Any or All.</param> /// <param name="currentRangeVariable">The newest range variable added for by this Any or All.</param> protected LambdaNode(Collection <RangeVariable> rangeVariables, RangeVariable currentRangeVariable) { this.rangeVariables = rangeVariables; this.currentRangeVariable = currentRangeVariable; }