/// <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;
        }
Exemple #10
0
        /// <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);
        }
Exemple #11
0
 public QueryExpressionVisitor(QueryContext context)
 {
     this.context         = new QueryExpressionContext(context);
     processedExpressions = new Dictionary <Expression, Expression>();
 }