/// <summary> /// Binds a collection of <paramref name="segments"/> to metadata, creating a semantic ODataPath object. /// </summary> /// <param name="segments">Collection of path segments.</param> /// <param name="configuration">The configuration to use when binding the path.</param> /// <returns>A semantic <see cref="ODataPath"/> object to describe the path.</returns> internal static ODataPath BindPath(ICollection<string> segments, ODataUriParserConfiguration configuration) { ODataPathParser semanticPathParser = new ODataPathParser(configuration); var intermediateSegments = semanticPathParser.ParsePath(segments); ODataPath path = new ODataPath(intermediateSegments); return path; }
/// <summary> /// Build the ExpandOption variant of an SelectExpandBinder /// </summary> /// <param name="configuration">The configuration used for binding.</param> /// <param name="edmType">The type of the top level expand item.</param> /// <param name="navigationSource">The navigation source of the top level expand item.</param> public SelectExpandBinder(ODataUriParserConfiguration configuration, IEdmStructuredType edmType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(edmType, "edmType"); this.configuration = configuration; this.edmType = edmType; this.navigationSource = navigationSource; }
/// <summary> /// Tries to parse a collection of function parameters for path. /// </summary> /// <param name="parenthesisExpression">The contents of the parentheses portion of the current path segment.</param> /// <param name="configuration">The ODataUriParserConfiguration to create a UriQueryExpressionParser.</param> /// <param name="splitParameters">The parameters if they were successfully split.</param> /// <returns>Whether the parameters could be split.</returns> internal static bool TrySplitOperationParameters(string parenthesisExpression, ODataUriParserConfiguration configuration, out ICollection<FunctionParameterToken> splitParameters) { ExpressionLexer lexer = new ExpressionLexer(parenthesisExpression, true /*moveToFirstToken*/, false /*useSemicolonDelimeter*/, true /*parsingFunctionParameters*/); UriQueryExpressionParser parser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, lexer); var ret = parser.TrySplitOperationParameters(ExpressionTokenKind.End, out splitParameters); // check duplicate names if (splitParameters.Select(t => t.ParameterName).Distinct().Count() != splitParameters.Count) { throw new ODataException(ODataErrorStrings.FunctionCallParser_DuplicateParameterOrEntityKeyName); } return ret; }
public void ParseMultipleTransformations(string query) { var model = Common.TestModelBuilder.CreateModel(new Type[] { typeof(Category), typeof(Product), typeof(Sales) }); IEdmType edmType = model.FindDeclaredType(typeof(Sales).FullName); var config = new ODataUriParserConfiguration(model); var result = default(ApplyClause); "Given a message to parse {0}".Given(() => { }); "When I try to parse".When( () => { result = ApplyParser.ParseApplyImplementation(query, config, edmType, null); }); "we should find 4 transformations".Then(() => result.Transformations.Count.Should().Be(4)); "the first transformation is aggregate".Then(() => result.Transformations.First().Item2.Should().BeOfType <ApplyAggregateClause>()); "the last transformation is groupby".Then(() => result.Transformations.Last().Item2.Should().BeOfType <ApplyGroupbyClause>()); }
private static bool TryParseOperationParameters(string functionName, string parenthesisExpression, ParameterAliasValueAccessor paramAliasAccessor, IEdmOperation operation, out ICollection <OperationSegmentParameter> parsedSegementParameters) { ICollection <FunctionParameterToken> splitParameters; parsedSegementParameters = null; ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(HardCodedTestModel.TestModel) { ParameterAliasValueAccessor = paramAliasAccessor, EnableCaseInsensitiveUriFunctionIdentifier = false }; if (FunctionParameterParser.TrySplitOperationParameters(parenthesisExpression, configuration, out splitParameters)) { parsedSegementParameters = FunctionCallBinder.BindSegmentParameters(configuration, operation, splitParameters); return(true); } return(false); }
private static bool TryParseOperationParameters(string functionName, string parenthesisExpression, IEdmOperation operation, out ICollection <OperationSegmentParameter> parsedSegementParameters, bool enableUriTemplateParsing = false) { ICollection <FunctionParameterToken> splitParameters; parsedSegementParameters = null; ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(HardCodedTestModel.TestModel) { EnableUriTemplateParsing = enableUriTemplateParsing }; if (FunctionParameterParser.TrySplitOperationParameters(parenthesisExpression, configuration, out splitParameters)) { parsedSegementParameters = FunctionCallBinder.BindSegmentParameters(configuration, operation, splitParameters); return(true); } return(false); }
/// <summary> /// Parse an apply query /// </summary> /// <param name="applyQuery">The apply query</param> /// <param name="oDataUriParserConfiguration"></param> /// <param name="edmType">the EDM type of the entity set</param> /// <param name="edmNavigationSource"></param> /// <returns>an <see cref="ApplyClause"/> that contains a list of transformation clause objects as a List of Tuples /// where item1 is the transformation name and item2 is the relevant Clause object as <see cref="AggregationTransformationBase"/></returns> internal static ApplyClause ParseApplyImplementation(string applyQuery, ODataUriParserConfiguration oDataUriParserConfiguration, IEdmType edmType, IEdmNavigationSource edmNavigationSource) { var res = new ApplyClause(); if (applyQuery.StartsWith(UriQueryConstants.ApplyQueryOption)) { applyQuery = applyQuery.Substring(7); } var trasformations = new List <Tuple <string, AggregationTransformationBase> >(); List <Tuple <string, string> > trasformationsToParse = GetTransformations(applyQuery); foreach (var transformationPair in trasformationsToParse) { var trasformationName = transformationPair.Item2; var trasformationQuery = transformationPair.Item1; switch (trasformationName) { case UriQueryConstants.AggregateTransformation: trasformations.Add(new Tuple <string, AggregationTransformationBase>( UriQueryConstants.AggregateTransformation, ParseAggregate(res, trasformationQuery, oDataUriParserConfiguration, edmType, edmNavigationSource))); break; case UriQueryConstants.GroupbyTransformation: trasformations.Add(new Tuple <string, AggregationTransformationBase>( UriQueryConstants.GroupbyTransformation, ParseGroupBy(res, trasformationQuery, oDataUriParserConfiguration, edmType, edmNavigationSource))); break; case UriQueryConstants.FilterTransformation: trasformations.Add(new Tuple <string, AggregationTransformationBase>( UriQueryConstants.FilterTransformation, ParseFilter(res, trasformationQuery, oDataUriParserConfiguration, edmType, edmNavigationSource))); break; default: throw new ODataException("Unsupported aggregation transformation"); } } res.Transformations = trasformations; return(res); }
private ExpandToken StarExpandTesting(string expand, String entitySetType) { IEdmModel model = Microsoft.Test.OData.Utils.Metadata.TestModels.BuildTestModel(); ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(EdmCoreModel.Instance) { Settings = { PathLimit = 10, FilterLimit = 10, OrderByLimit = 10, SearchLimit = 10, SelectExpandLimit = 10 } }; var parentEntityType = configuration.Resolver.ResolveNavigationSource(model, entitySetType).EntityType(); SelectExpandParser expandParser = new SelectExpandParser(configuration.Resolver, expand, parentEntityType, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier) { MaxPathDepth = configuration.Settings.PathLimit, MaxFilterDepth = configuration.Settings.FilterLimit, MaxOrderByDepth = configuration.Settings.OrderByLimit, MaxSearchDepth = configuration.Settings.SearchLimit }; return(expandParser.ParseExpand()); }
public void ParseAggregate(string query) { var model = Common.TestModelBuilder.CreateModel(new Type[] { typeof(Category), typeof(Product), typeof(Sales) }); IEdmType edmType = model.FindDeclaredType(typeof(Sales).FullName); var config = new ODataUriParserConfiguration(model); var result = default(ApplyClause); "Given a message to parse {0}".Given(() => { }); "When I try to parse".When( () => { result = ApplyParser.ParseApplyImplementation(query, config, edmType, null); }); "The transformation is aggregate".Then(() => result.Transformations.First().Item2.Should().BeOfType <ApplyAggregateClause>()); "The Alias is Total".Then(() => ((ApplyAggregateClause)result.Transformations.First().Item2).Alias.Should().Be("Total")); "The aggregation method is Sum".Then(() => ((ApplyAggregateClause)result.Transformations.First().Item2).AggregationMethod.Should().Be("sum")); "The aggregation expression exist".Then(() => ((ApplyAggregateClause)result.Transformations.First().Item2).AggregatablePropertyExpression.Expression.Should().NotBeNull()); "The aggregation expression type exist".Then(() => ((ApplyAggregateClause)result.Transformations.First().Item2).AggregatablePropertyExpression.ItemType.Should().NotBeNull()); }
public void ParentEntityTypeIsNullForExpandStar() { var expand = "*"; ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(EdmCoreModel.Instance) { Settings = { PathLimit = 10, FilterLimit = 10, OrderByLimit = 10, SearchLimit = 10, SelectExpandLimit = 10 } }; SelectExpandParser expandParser = new SelectExpandParser(configuration.Resolver, expand, null, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier) { MaxPathDepth = configuration.Settings.PathLimit, MaxFilterDepth = configuration.Settings.FilterLimit, MaxOrderByDepth = configuration.Settings.OrderByLimit, MaxSearchDepth = configuration.Settings.SearchLimit }; Action action = () => expandParser.ParseExpand(); action.ShouldThrow <ODataException>().WithMessage(Strings.UriExpandParser_ParentEntityIsNull("")); }
/// <summary> /// Add semantic meaning to a Select or Expand Token /// </summary> /// <param name="elementType">the top level entity type.</param> /// <param name="navigationSource">the top level navigation source</param> /// <param name="expandToken">the syntactically parsed expand token</param> /// <param name="selectToken">the syntactically parsed select token</param> /// <param name="configuration">The configuration to use for parsing.</param> /// <returns>A select expand clause bound to metadata.</returns> public SelectExpandClause Bind( IEdmStructuredType elementType, IEdmNavigationSource navigationSource, ExpandToken expandToken, SelectToken selectToken, ODataUriParserConfiguration configuration) { ExpandToken unifiedSelectExpandToken = SelectExpandSyntacticUnifier.Combine(expandToken, selectToken); ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer(); ExpandToken normalizedSelectExpandToken = expandTreeNormalizer.NormalizeExpandTree(unifiedSelectExpandToken); SelectExpandBinder selectExpandBinder = new SelectExpandBinder(configuration, elementType, navigationSource); SelectExpandClause clause = selectExpandBinder.Bind(normalizedSelectExpandToken); SelectExpandClauseFinisher.AddExplicitNavPropLinksWhereNecessary(clause); new ExpandDepthAndCountValidator(configuration.Settings.MaximumExpansionDepth, configuration.Settings.MaximumExpansionCount).Validate(clause); return(clause); }
/// <summary> /// Add semantic meaning to a Select or Expand Token /// </summary> /// <param name="elementType">the top level entity type.</param> /// <param name="navigationSource">the top level navigation source</param> /// <param name="expandToken">the syntactically parsed expand token</param> /// <param name="selectToken">the syntactically parsed select token</param> /// <param name="configuration">The configuration to use for parsing.</param> /// <returns>A select expand clause bound to metadata.</returns> public SelectExpandClause Bind( IEdmStructuredType elementType, IEdmNavigationSource navigationSource, ExpandToken expandToken, SelectToken selectToken, ODataUriParserConfiguration configuration) { ExpandToken unifiedSelectExpandToken = SelectExpandSyntacticUnifier.Combine(expandToken, selectToken); ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer(); ExpandToken normalizedSelectExpandToken = expandTreeNormalizer.NormalizeExpandTree(unifiedSelectExpandToken); SelectExpandBinder selectExpandBinder = new SelectExpandBinder(configuration, elementType, navigationSource); SelectExpandClause clause = selectExpandBinder.Bind(normalizedSelectExpandToken); SelectExpandClauseFinisher.AddExplicitNavPropLinksWhereNecessary(clause); new ExpandDepthAndCountValidator(configuration.Settings.MaximumExpansionDepth, configuration.Settings.MaximumExpansionCount).Validate(clause); return clause; }
/// <summary> /// Parse the raw select and expand strings into Abstract Syntax Trees /// </summary> /// <param name="selectClause">The raw select string</param> /// <param name="expandClause">the raw expand string</param> /// <param name="configuration">Configuration parameters</param> /// <param name="expandTree">the resulting expand AST</param> /// <param name="selectTree">the resulting select AST</param> public static void Parse( string selectClause, string expandClause, ODataUriParserConfiguration configuration, out ExpandToken expandTree, out SelectToken selectTree) { SelectExpandParser selectParser = new SelectExpandParser(selectClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveBuiltinIdentifier) { MaxPathDepth = configuration.Settings.PathLimit }; selectTree = selectParser.ParseSelect(); SelectExpandParser expandParser = new SelectExpandParser(expandClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveBuiltinIdentifier) { MaxPathDepth = configuration.Settings.PathLimit, MaxFilterDepth = configuration.Settings.FilterLimit, MaxOrderByDepth = configuration.Settings.OrderByLimit, MaxSearchDepth = configuration.Settings.SearchLimit }; expandTree = expandParser.ParseExpand(); }
/// <summary> /// Parse the raw select and expand strings into Abstract Syntax Trees /// </summary> /// <param name="selectClause">the raw select string</param> /// <param name="expandClause">the raw expand string</param> /// <param name="parentEntityType">the parent entity type for expand option</param> /// <param name="configuration">the OData URI parser configuration</param> /// <param name="expandTree">the resulting expand AST</param> /// <param name="selectTree">the resulting select AST</param> public static void Parse( string selectClause, string expandClause, IEdmStructuredType parentEntityType, ODataUriParserConfiguration configuration, out ExpandToken expandTree, out SelectToken selectTree) { SelectExpandParser selectParser = new SelectExpandParser(selectClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier) { MaxPathDepth = configuration.Settings.PathLimit }; selectTree = selectParser.ParseSelect(); SelectExpandParser expandParser = new SelectExpandParser(configuration.Resolver, expandClause, parentEntityType, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier) { MaxPathDepth = configuration.Settings.PathLimit, MaxFilterDepth = configuration.Settings.FilterLimit, MaxOrderByDepth = configuration.Settings.OrderByLimit, MaxSearchDepth = configuration.Settings.SearchLimit }; expandTree = expandParser.ParseExpand(); }
private ExpandToken StarExpandTesting(string expand, string typeName, IEdmModel model = null) { if (model == null) { model = Test.OData.Utils.Metadata.TestModels.BuildTestModel(); } ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(EdmCoreModel.Instance) { Settings = { PathLimit = 10, FilterLimit = 10, OrderByLimit = 10, SearchLimit = 10, SelectExpandLimit = 10 } }; var parentStructuredType = configuration.Resolver.ResolveType(model, "TestModel." + typeName) as IEdmStructuredType; SelectExpandParser expandParser = new SelectExpandParser(configuration.Resolver, expand, parentStructuredType, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier) { MaxPathDepth = configuration.Settings.PathLimit, MaxFilterDepth = configuration.Settings.FilterLimit, MaxOrderByDepth = configuration.Settings.OrderByLimit, MaxSearchDepth = configuration.Settings.SearchLimit }; return(expandParser.ParseExpand()); }
/// <summary> /// Parse the raw select and expand strings into Abstract Syntax Trees /// </summary> /// <param name="selectClause">The raw select string</param> /// <param name="expandClause">the raw expand string</param> /// <param name="configuration">Configuration parameters</param> /// <param name="expandTree">the resulting expand AST</param> /// <param name="selectTree">the resulting select AST</param> public static void Parse( string selectClause, string expandClause, ODataUriParserConfiguration configuration, out ExpandToken expandTree, out SelectToken selectTree) { SelectExpandParser selectParser = new SelectExpandParser(selectClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveBuiltinIdentifier) { MaxPathDepth = configuration.Settings.PathLimit }; selectTree = selectParser.ParseSelect(); SelectExpandParser expandParser = new SelectExpandParser(expandClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveBuiltinIdentifier) { MaxPathDepth = configuration.Settings.PathLimit, MaxFilterDepth = configuration.Settings.FilterLimit, MaxOrderByDepth = configuration.Settings.OrderByLimit, MaxSearchDepth = configuration.Settings.SearchLimit }; expandTree = expandParser.ParseExpand(); }
/// <summary> /// Constructs a <see cref="BindingState"/> with the given <paramref name="configuration"/>. /// </summary> /// <param name="configuration">The configuration used for binding.</param> internal BindingState(ODataUriParserConfiguration configuration) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); this.configuration = configuration; this.BindingRecursionDepth = 0; }
/// <summary> /// Initializes a new instance of <see cref="ODataPathParser"/>. /// </summary> /// <param name="configuration">The parser's current configuration.</param> internal ODataPathParser(ODataUriParserConfiguration configuration) { Debug.Assert(configuration != null, "configuration != null"); this.configuration = configuration; }
/// <summary> /// Tries to find a single matching operation import for the given identifier, parametes, and binding type. /// </summary> /// <param name="identifier">The identifier from the URI.</param> /// <param name="parenthesisExpression">The parenthesis expression contianing parameters, if any.</param> /// <param name="bindingType">The current binding type or null if there isn't one.</param> /// <param name="configuration">The configuration of the parser.</param> /// <param name="boundParameters">The parsed parameters from the parenthesis expression.</param> /// <param name="matchingOperation">The single matching operation import if one could be determined.</param> /// <returns>Whether or not a matching operation import could be found.</returns> private static bool TryBindingParametersAndMatchingOperation(string identifier, string parenthesisExpression, IEdmType bindingType, ODataUriParserConfiguration configuration, out ICollection<OperationSegmentParameter> boundParameters, out IEdmOperation matchingOperation) { // If the name isn't fully qualified then it can't be a function or action. // When using extension, there may be function call with unqualified name. So loose the restriction here. if (identifier != null && identifier.IndexOf(".", StringComparison.Ordinal) == -1 && configuration.Resolver.GetType() == typeof(ODataUriResolver)) { boundParameters = null; matchingOperation = null; return false; } // TODO: update code that is duplicate between operation and operation import, add more tests. matchingOperation = null; ICollection<FunctionParameterToken> splitParameters; if (!String.IsNullOrEmpty(parenthesisExpression)) { if (!FunctionParameterParser.TrySplitOperationParameters(parenthesisExpression, configuration, out splitParameters)) { IEdmOperation possibleMatchingOperation = null; // Look for an overload that returns an entity collection by the specified name. If so parthensis is just key parameters. if (FunctionOverloadResolver.ResolveOperationFromList(identifier, new List<string>(), bindingType, configuration.Model, out possibleMatchingOperation, configuration.Resolver)) { IEdmCollectionTypeReference collectionReturnType = possibleMatchingOperation.ReturnType as IEdmCollectionTypeReference; if (collectionReturnType != null && collectionReturnType.ElementType().IsEntity()) { matchingOperation = possibleMatchingOperation; boundParameters = null; return true; } else { throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_SegmentDoesNotSupportKeyPredicates(identifier)); } } boundParameters = null; return false; } } else { splitParameters = new Collection<FunctionParameterToken>(); } // Resolve the specific overload. if (FunctionOverloadResolver.ResolveOperationFromList(identifier, splitParameters.Select(k => k.ParameterName).ToList(), bindingType, configuration.Model, out matchingOperation, configuration.Resolver)) { boundParameters = FunctionCallBinder.BindSegmentParameters(configuration, matchingOperation, splitParameters); return true; } boundParameters = null; return false; }
/// <summary> /// Tries to find a single matching operation import for the given identifier, and parameters. /// </summary> /// <param name="identifier">The identifier from the URI.</param> /// <param name="parenthesisExpression">The parenthesis expression contianing parameters, if any.</param> /// <param name="configuration">The configuration of the parser.</param> /// <param name="boundParameters">The parsed parameters from the parenthesis expression.</param> /// <param name="matchingFunctionImport">The single matching operation import if one could be determined.</param> /// <returns>Whether or not a matching operation import could be found.</returns> private static bool TryBindingParametersAndMatchingOperationImport(string identifier, string parenthesisExpression, ODataUriParserConfiguration configuration, out ICollection<OperationSegmentParameter> boundParameters, out IEdmOperationImport matchingFunctionImport) { matchingFunctionImport = null; ICollection<FunctionParameterToken> splitParameters = null; if (!String.IsNullOrEmpty(parenthesisExpression)) { if (!FunctionParameterParser.TrySplitOperationParameters(parenthesisExpression, configuration, out splitParameters)) { IEdmOperationImport possibleMatchingOperationImport = null; // Look for an overload that returns an entity collection by the specified name. If so parthensis is just key parameters. if (FunctionOverloadResolver.ResolveOperationImportFromList(identifier, EmptyList, configuration.Model, out possibleMatchingOperationImport, configuration.Resolver)) { IEdmCollectionTypeReference collectionReturnType = possibleMatchingOperationImport.Operation.ReturnType as IEdmCollectionTypeReference; if (collectionReturnType != null && collectionReturnType.ElementType().IsEntity()) { matchingFunctionImport = possibleMatchingOperationImport; boundParameters = null; return true; } else { throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_SegmentDoesNotSupportKeyPredicates(identifier)); } } boundParameters = null; return false; } } else { splitParameters = new Collection<FunctionParameterToken>(); } // Resolve the specific overload. if (FunctionOverloadResolver.ResolveOperationImportFromList(identifier, splitParameters.Select(k => k.ParameterName).ToList(), configuration.Model, out matchingFunctionImport, configuration.Resolver)) { var matchingOperation = matchingFunctionImport.Operation; boundParameters = FunctionCallBinder.BindSegmentParameters(configuration, matchingOperation, splitParameters); return true; } boundParameters = null; return false; }
internal static List<OperationSegmentParameter> BindSegmentParameters(ODataUriParserConfiguration configuration, IEdmOperation functionOrOpertion, ICollection<FunctionParameterToken> segmentParameterTokens) { // TODO: HandleComplexOrCollectionParameterValueIfExists is temp work around for single copmlex or colleciton type, it can't handle nested complex or collection value. ICollection<FunctionParameterToken> parametersParsed = FunctionCallBinder.HandleComplexOrCollectionParameterValueIfExists(configuration.Model, functionOrOpertion, segmentParameterTokens, configuration.Resolver.EnableCaseInsensitive, configuration.EnableUriTemplateParsing); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = null; state.RangeVariables.Clear(); MetadataBinder binder = new MetadataBinder(state); List<OperationSegmentParameter> boundParameters = new List<OperationSegmentParameter>(); IDictionary<string, SingleValueNode> input = new Dictionary<string, SingleValueNode>(StringComparer.Ordinal); foreach (var paraToken in parametersParsed) { // TODO: considering another better exception if (paraToken.ValueToken is EndPathToken) { throw new ODataException(Strings.MetadataBinder_ParameterNotInScope( string.Format(CultureInfo.InvariantCulture, "{0}={1}", paraToken.ParameterName, (paraToken.ValueToken as EndPathToken).Identifier))); } SingleValueNode boundNode = (SingleValueNode)binder.Bind(paraToken.ValueToken); if (!input.ContainsKey(paraToken.ParameterName)) { input.Add(paraToken.ParameterName, boundNode); } } IDictionary<IEdmOperationParameter, SingleValueNode> result = configuration.Resolver.ResolveOperationParameters(functionOrOpertion, input); foreach (var item in result) { SingleValueNode boundNode = item.Value; // ensure node type is compatible with parameter type. var sourceTypeReference = boundNode.GetEdmTypeReference(); bool sourceIsNullOrOpenType = (sourceTypeReference == null); if (!sourceIsNullOrOpenType) { // if the node has been rewritten, no further conversion is needed. if (!TryRewriteIntegralConstantNode(ref boundNode, item.Key.Type)) { boundNode = MetadataBindingUtils.ConvertToTypeIfNeeded(boundNode, item.Key.Type); } } OperationSegmentParameter boundParamer = new OperationSegmentParameter(item.Key.Name, boundNode); boundParameters.Add(boundParamer); } return boundParameters; }
/// <summary> /// Parse queries such as : "groupby(Customer/Name,Customer/ID,Product/Name,Account)" or "groupby((Customer/Country,Product/Name), aggregate(Amount with sum as Total))" /// </summary> /// <param name="apply"></param> /// <param name="query"></param> /// <param name="oDataUriParserConfiguration"></param> /// <param name="edmType"></param> /// <param name="edmNavigationSource"></param> /// <returns></returns> private static ApplyGroupbyClause ParseGroupBy(ApplyClause apply, string query, ODataUriParserConfiguration oDataUriParserConfiguration, IEdmType edmType, IEdmNavigationSource edmNavigationSource) { string selectQuery; ApplyAggregateClause aggregateClause = null; query = IsolateQuery(query, UriQueryConstants.GroupbyTransformation); if (query.StartsWith("(") && query.EndsWith(")")) { query = query.TrimOne('(', ')'); } var p = query.IndexOf(UriQueryConstants.AggregateTransformation + '('); if (p == -1) { if (query.StartsWith("(") && query.EndsWith(")")) { query = query.TrimOne('(', ')'); } selectQuery = query; } else { selectQuery = query.Substring(0, p).Trim().Trim(',').TrimOne('(', ')'); aggregateClause = ParseAggregate(apply, query.Substring(p), oDataUriParserConfiguration, edmType, edmNavigationSource); } var selectedStatements = selectQuery.Split(','); var withIndex = selectQuery.IndexOf("with"); if (withIndex > 0) { selectedStatements = selectQuery.Substring(0, withIndex).Split(','); var withStatement = selectQuery.Substring(withIndex, selectQuery.Length - withIndex); selectedStatements[selectedStatements.Count() - 1] = selectedStatements[selectedStatements.Count() - 1] + withStatement; } string aggregationMethod, alias; List <ExpressionClause> aggregatablePropertyExpressions = null; try { aggregatablePropertyExpressions = selectedStatements.Select(statement => ODataQueryOptionParser.ParseExpressionImplementation( GetAggregatableProperty(statement, false, out alias, out aggregationMethod), oDataUriParserConfiguration, edmType, edmNavigationSource)).ToList(); } catch (Exception) { //parsing of some expressions (like property on enum such as DateTimeOffset/Minute) are not supported so ODataQueryOptionParser.ParseExpressionImplementation will fail aggregatablePropertyExpressions = null; } return(new ApplyGroupbyClause() { SelectedStatements = selectedStatements, SelectedPropertiesExpressions = aggregatablePropertyExpressions, Aggregate = aggregateClause, Apply = apply }); }
/// <summary> /// Parse queries such as: /// "aggregate(Amount with sum as Total)" and "aggregate(Amount mul Product/TaxRate with sum as Tax)" /// </summary> /// <param name="apply"></param> /// <param name="query"></param> /// <param name="oDataUriParserConfiguration"></param> /// <param name="edmType"></param> /// <param name="edmNavigationSource"></param> /// <returns></returns> private static ApplyAggregateClause ParseAggregate(ApplyClause apply, string query, ODataUriParserConfiguration oDataUriParserConfiguration, IEdmType edmType, IEdmNavigationSource edmNavigationSource) { query = IsolateQuery(query, UriQueryConstants.AggregateTransformation); string aggregatableProperty; string aggregationMethod; string alias; aggregatableProperty = GetAggregatableProperty(query, true, out alias, out aggregationMethod); //create an projection Expression to the property var AggregatablePropertyExpression = ODataQueryOptionParser.ParseExpressionImplementation( aggregatableProperty, oDataUriParserConfiguration, edmType, edmNavigationSource); return(new ApplyAggregateClause() { AggregatablePropertyExpression = AggregatablePropertyExpression, Alias = alias, AggregationMethod = aggregationMethod, AggregatableProperty = aggregatableProperty, Apply = apply }); }
public ApplyBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo) { this.bindMethod = bindMethod; this.state = state; this.filterBinder = new FilterBinder(bindMethod, state); this.configuration = configuration; this.odataPathInfo = odataPathInfo; }
/// <summary> /// Bind a select and expand option. /// </summary> /// <param name="syntax">A syntax tree containing the select and expand options to bind</param> /// <param name="path">the top level path</param> /// <param name="configuration">The configuration to use for binding.</param> /// <returns>a select expand clause bound to metadata</returns> public static SelectExpandClause BindSelectExpand(SyntacticTree syntax, ODataPath path, ODataUriParserConfiguration configuration) { if (syntax.Select != null || syntax.Expand != null) { if (!path.EdmType().IsEntityCollection() && !path.EdmType().IsEntity()) { throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$select or $expand")); } SelectExpandSemanticBinder semanticBinder = new SelectExpandSemanticBinder(); return(semanticBinder.Bind((IEdmEntityType)((IEdmCollectionTypeReference)path.EdmType()).ElementType().Definition, path.NavigationSource(), syntax.Expand, syntax.Select, configuration)); } return(null); }
/// <summary> /// Constructs a <see cref="BindingState"/> with the given <paramref name="configuration"/>. /// </summary> /// <param name="configuration">The configuration used for binding.</param> internal BindingState(ODataUriParserConfiguration configuration) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); this.configuration = configuration; this.BindingRecursionDepth = 0; }
/// <summary> /// Build an ExpandBinder based on global settings /// </summary> /// <param name="elementType">The entity type of the top level expand item.</param> /// <param name="entitySet">The entity set of the top level expand item.</param> /// <param name="configuration">The configuration to use for binding.</param> /// <returns>An ExpandBinder strategy based on the global settings</returns> public static ExpandBinder Create(IEdmEntityType elementType, IEdmEntitySet entitySet, ODataUriParserConfiguration configuration) { Debug.Assert(configuration != null, "configuration != null"); Debug.Assert(configuration.Settings != null, "configuration.Settings != null"); if (configuration.Settings.SupportExpandOptions) { return(new ExpandOptionExpandBinder(configuration, elementType, entitySet)); } else { return(new NonOptionExpandBinder(configuration, elementType, entitySet)); } }
/// <summary> /// Tries to parse a collection of function parameters for path. /// </summary> /// <param name="functionName">The function name to use in error messages.</param> /// <param name="parenthesisExpression">The contents of the parentheses portion of the current path segment.</param> /// <param name="configuration">The ODataUriParserConfiguration to create a UriQueryExpressionParser.</param> /// <param name="splitParameters">The parameters if they were successfully split.</param> /// <returns>Whether the parameters could be split.</returns> internal static bool TrySplitOperationParameters(string functionName, string parenthesisExpression, ODataUriParserConfiguration configuration, out ICollection <FunctionParameterToken> splitParameters) { ExpressionLexer lexer = new ExpressionLexer(parenthesisExpression, true /*moveToFirstToken*/, false /*useSemicolonDelimeter*/, true /*parsingFunctionParameters*/); UriQueryExpressionParser parser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, lexer); var ret = parser.TrySplitOperationParameters(ExpressionTokenKind.End, out splitParameters); // check duplicate names if (splitParameters.Select(t => t.ParameterName).Distinct().Count() != splitParameters.Count) { throw new ODataException(ODataErrorStrings.FunctionCallParser_DuplicateParameterName); } return(ret); }
/// <summary> /// Build the NonOption variant of an ExpandBinder /// </summary> /// <param name="configuration">The configuration used for binding.</param> /// <param name="entityType">The entity type of the top level expand item.</param> /// <param name="entitySet">The entity set of the top level expand item.</param> public NonOptionExpandBinder(ODataUriParserConfiguration configuration, IEdmEntityType entityType, IEdmEntitySet entitySet) : base(configuration, entityType, entitySet) { }
/// <summary> /// Create a ApplyFilterClause from a parse transformation query /// </summary> /// <param name="apply"></param> /// <param name="query"></param> /// <param name="oDataUriParserConfiguration"></param> /// <param name="edmType"></param> /// <param name="edmNavigationSource"></param> /// <returns></returns> private static ApplyFilterClause ParseFilter(ApplyClause apply, string query, ODataUriParserConfiguration oDataUriParserConfiguration, IEdmType edmType, IEdmNavigationSource edmNavigationSource) { query = IsolateQuery(query, UriQueryConstants.FilterTransformation); return(new ApplyFilterClause() { Apply = apply, Filter = ODataQueryOptionParser.ParseFilterImplementation( query, oDataUriParserConfiguration, edmType, edmNavigationSource), RawQueryString = query }); }