/// <summary> /// Initializes a new instance of the <see cref="ApiDataReference" /> class. /// </summary> /// <param name="context"> /// A query context. /// </param> /// <param name="name"> /// The name of an entity set, singleton or function import. /// </param> public ApiDataReference(QueryContext context, string name) { Ensure.NotNull(context, "context"); Ensure.NotNull(name, "name"); this.context = context; this.name = name; }
/// <summary> /// Initializes a new instance of the <see cref="DataSourceStubModelReference" /> class. /// </summary> /// <param name="context"> /// A query context. /// </param> /// <param name="name"> /// The name of an entity set, singleton or function import. /// </param> internal DataSourceStubModelReference(QueryContext context, string name) { Ensure.NotNull(context, "context"); Ensure.NotNull(name, "name"); this.context = context; this.name = name; }
/// <summary> /// Initializes a new instance of the <see cref="DataSourceStubReference" /> class referring to a function. /// </summary> /// <param name="context"> /// A query context. /// </param> /// <param name="namespaceName"> /// The name of a namespace containing the function. /// </param> /// <param name="name"> /// The name of a function. /// </param> public DataSourceStubReference( QueryContext context, string namespaceName, string name) { Ensure.NotNull(context, "context"); Ensure.NotNull(namespaceName, "namespaceName"); Ensure.NotNull(name, "name"); this.context = context; this.namespaceName = namespaceName; this.name = name; }
/// <summary> /// Initializes a new instance of the <see cref="QueryExpressionContext" /> class. /// </summary> /// <param name="queryContext"> /// A query context. /// </param> public QueryExpressionContext(QueryContext queryContext) { Ensure.NotNull(queryContext, "queryContext"); this.QueryContext = queryContext; }
/// <summary> /// Asynchronously executes the query flow. /// </summary> /// <param name="context"> /// The query context. /// </param> /// <param name="cancellationToken"> /// A cancellation token. /// </param> /// <returns> /// A task that represents the asynchronous /// operation whose result is a query result. /// </returns> public static async Task<QueryResult> QueryAsync( QueryContext context, CancellationToken cancellationToken) { Ensure.NotNull(context, "context"); // process query expression var expression = context.Request.Expression; var visitor = new QueryExpressionVisitor(context); expression = visitor.Visit(expression); // get element type Type elementType = null; var queryType = expression.Type.FindGenericType(typeof(IQueryable<>)); if (queryType != null) { elementType = queryType.GetGenericArguments()[0]; } // append count expression if requested if (elementType != null && context.Request.ShouldReturnCount) { expression = ExpressionHelpers.Count(expression, elementType); elementType = null; // now return type is single int } // execute query QueryResult result; var executor = context.GetHookHandler<IQueryExecutor>(); if (executor == null) { throw new NotSupportedException(Resources.QueryExecutorMissing); } if (elementType != null) { var query = visitor.BaseQuery.Provider.CreateQuery(expression); var method = typeof(IQueryExecutor) .GetMethod("ExecuteQueryAsync") .MakeGenericMethod(elementType); var parameters = new object[] { context, query, cancellationToken }; var task = method.Invoke(executor, parameters) as Task<QueryResult>; result = await task; } else { var method = typeof(IQueryExecutor) .GetMethod("ExecuteSingleAsync") .MakeGenericMethod(expression.Type); var parameters = new object[] { context, visitor.BaseQuery, expression, cancellationToken }; var task = method.Invoke(executor, parameters) as Task<QueryResult>; result = await task; } if (result != null) { result.ResultsSource = visitor.EntitySet; } return result; }
public QueryExpressionVisitor(QueryContext context) { this.context = new QueryExpressionContext(context); this.processedExpressions = new Dictionary<Expression, Expression>(); }
private static async Task ExecuteSubExpression( QueryContext context, CancellationToken cancellationToken, QueryExpressionVisitor visitor, IQueryExecutor executor, Expression expression) { // get element type Type elementType = null; var queryType = expression.Type.FindGenericType(typeof(IQueryable<>)); if (queryType != null) { elementType = queryType.GetGenericArguments()[0]; } var query = visitor.BaseQuery.Provider.CreateQuery(expression); var method = typeof(IQueryExecutor) .GetMethod("ExecuteQueryAsync") .MakeGenericMethod(elementType); var parameters = new object[] { context, query, cancellationToken }; var task = method.Invoke(executor, parameters) as Task<QueryResult>; var result = await task; var any = result.Results.Cast<object>().Any(); if (!any) { // Which means previous expression does not have result, and should throw ResourceNotFoundException. throw new ResourceNotFoundException(Resources.ResourceNotFound); } }
private static async Task CheckSubExpressionResult( QueryContext context, CancellationToken cancellationToken, IEnumerable enumerableResult, QueryExpressionVisitor visitor, IQueryExecutor executor, Expression expression) { if (enumerableResult.GetEnumerator().MoveNext()) { // If there is some result, will not have additional processing return; } var methodCallExpression = expression as MethodCallExpression; // This will remove unneeded statement which includes $expand, $select,$top,$skip,$orderby methodCallExpression = methodCallExpression.RemoveUnneededStatement(); if (methodCallExpression == null || methodCallExpression.Arguments.Count != 2) { return; } if (methodCallExpression.Method.Name == ExpressionMethodNameOfWhere) { // Throw exception if key as last where statement, or remove $filter where statement methodCallExpression = CheckWhereCondition(methodCallExpression); if (methodCallExpression == null || methodCallExpression.Arguments.Count != 2) { return; } // Call without $filter where statement and with Key where statement if (methodCallExpression.Method.Name == ExpressionMethodNameOfWhere) { // The last where from $filter is removed and run with key where statement await ExecuteSubExpression(context, cancellationToken, visitor, executor, methodCallExpression); return; } } if (methodCallExpression.Method.Name != ExpressionMethodNameOfSelect && methodCallExpression.Method.Name != ExpressionMethodNameOfSelectMany) { // If last statement is not select property, will no further checking return; } var subExpression = methodCallExpression.Arguments[0]; // Remove appended statement like Where(Param_0 => (Param_0.Prop != null)) if there is one subExpression = subExpression.RemoveAppendWhereStatement(); await ExecuteSubExpression(context, cancellationToken, visitor, executor, subExpression); }
/// <summary> /// Asynchronously executes the query flow. /// </summary> /// <param name="context"> /// The query context. /// </param> /// <param name="cancellationToken"> /// A cancellation token. /// </param> /// <returns> /// A task that represents the asynchronous /// operation whose result is a query result. /// </returns> public async Task<QueryResult> QueryAsync( QueryContext context, CancellationToken cancellationToken) { Ensure.NotNull(context, "context"); // STEP 1: pre-filter var filters = context.GetHookPoints<IQueryFilter>(); foreach (var filter in filters.Reverse()) { await filter.FilterRequestAsync(context, cancellationToken); if (context.Result != null) { return context.Result; } } // STEP 2: process query expression var expression = context.Request.Expression; var visitor = new QueryExpressionVisitor(context); expression = visitor.Visit(expression); // STEP 3: execute query QueryResult result = null; var executor = context.GetHookPoint<IQueryExecutor>(); if (executor == null) { throw new NotSupportedException(); } var queryType = expression.Type .FindGenericType(typeof(IQueryable<>)); if (queryType != null) { var query = visitor.BaseQuery.Provider.CreateQuery(expression); var method = typeof(IQueryExecutor) .GetMethod("ExecuteQueryAsync") .MakeGenericMethod(queryType.GetGenericArguments()[0]); var parameters = new object[] { context, query, cancellationToken }; var task = method.Invoke(executor, parameters) as Task<QueryResult>; result = await task; } else { var method = typeof(IQueryExecutor) .GetMethod("ExecuteSingleAsync") .MakeGenericMethod(expression.Type); var parameters = new object[] { context, visitor.BaseQuery, expression, cancellationToken }; var task = method.Invoke(executor, parameters) as Task<QueryResult>; result = await task; } if (result != null) { result.ResultsSource = visitor.EntitySet; } context.Result = result; // STEP 4: post-filter foreach (var filter in filters) { await filter.FilterResultAsync(context, cancellationToken); } return context.Result; }
/// <summary> /// Asynchronously executes the query flow. /// </summary> /// <param name="context"> /// The query context. /// </param> /// <param name="cancellationToken"> /// A cancellation token. /// </param> /// <returns> /// A task that represents the asynchronous /// operation whose result is a query result. /// </returns> public static async Task <QueryResult> QueryAsync( QueryContext context, CancellationToken cancellationToken) { Ensure.NotNull(context, nameof(context)); // process query expression var expression = context.Request.Expression; var visitor = new QueryExpressionVisitor(context); expression = visitor.Visit(expression); // get element type Type elementType = null; var queryType = expression.Type.FindGenericType(typeof(IQueryable <>)); if (queryType != null) { elementType = queryType.GetGenericArguments()[0]; } // append count expression if requested if (elementType != null && context.Request.ShouldReturnCount) { expression = ExpressionHelpers.Count(expression, elementType); elementType = null; // now return type is single int } // execute query QueryResult result; var executor = context.GetApiService <IQueryExecutor>(); if (executor == null) { throw new NotSupportedException(Resources.QueryExecutorMissing); } if (elementType != null) { var query = visitor.BaseQuery.Provider.CreateQuery(expression); var method = typeof(IQueryExecutor) .GetMethod("ExecuteQueryAsync") .MakeGenericMethod(elementType); var parameters = new object[] { context, query, cancellationToken }; var task = method.Invoke(executor, parameters) as Task <QueryResult>; result = await task.ConfigureAwait(false); await CheckSubExpressionResult( context, result.Results, visitor, executor, expression, cancellationToken).ConfigureAwait(false); } else { var method = typeof(IQueryExecutor) .GetMethod("ExecuteExpressionAsync") .MakeGenericMethod(expression.Type); var parameters = new object[] { context, visitor.BaseQuery.Provider, expression, cancellationToken }; var task = method.Invoke(executor, parameters) as Task <QueryResult>; result = await task.ConfigureAwait(false); } if (result != null) { result.ResultsSource = visitor.EntitySet; } return(result); }
public QueryExpressionVisitor(QueryContext context) { this.context = new QueryExpressionContext(context); processedExpressions = new Dictionary <Expression, Expression>(); }