Пример #1
0
        /// <summary>
        /// Visits a <see cref="DeclareJobStatement"/>.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// The node, or a new version of the node.
        /// </returns>
        protected internal override Node VisitDeclareJobStatement([NotNull] DeclareJobStatement node)
        {
            base.VisitDeclareJobStatement(node);

            var context        = Expression.Parameter(typeof(IExecutionContext), "context");
            var replaceContext = GenericVisitor.Create((ExecutionContextExpression e) => context);

            var expr = Expression.Convert(
                Expression.NewArrayInit(
                    typeof(JobTrigger),
                    node.Triggers.Select(t =>
                                         Expression.New(
                                             typeof(JobTrigger).GetTypeInfo().DeclaredConstructors.First(),
                                             replaceContext.Visit(this.data.ConvertToLinqExpression(t.Function)),
                                             Expression.Constant(t.GetDisplay())))),
                typeof(IEnumerable <JobTrigger>)).RewriteTasksToAsyncExpression();

            if (!expr.Type.IsConstructedGenericType || expr.Type.GetGenericTypeDefinition() != typeof(Task <>))
            {
                var fromResult = typeof(Task).GetGenericMethod(nameof(Task.FromResult), (Type)null).MakeGenericMethod(typeof(IEnumerable <JobTrigger>));

                expr = Expression.Call(null, fromResult, expr);
            }

            var factories = Expression.Lambda <Func <IExecutionContext, Task <IEnumerable <IJobTrigger> > > >(expr, context).Compile();

            var plan = node.Statements.Count == 1
                           ? this.data.GetQueryPlan(node.Statements[0])
                           : new CombinedQueryPlan(node.Statements.Select(this.data.GetQueryPlan));

            this.data.SetQueryPlan(node, new DeclareJobPlan(node.Name, plan, factories));

            return(base.VisitDeclareJobStatement(node));
        }
Пример #2
0
        /// <summary>
        /// The get data async.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="multiPartQuery">
        /// The multi part query.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        internal override IAsyncEnumerable <Row> GetRows(IInternalExecutionContext context, [NotNull] IMultiPartQuery multiPartQuery)
        {
            var fieldReplacer = GenericVisitor.Create((SourceFieldExpression e) => CustomExpression.MakeField(e.SourceName, e.FieldName, e.Type));

            var query =
                multiPartQuery.WildcardAliases.Contains(this.alias) ?
                new Query(
                    fieldReplacer.Visit(multiPartQuery.FilterExpression),
                    multiPartQuery.OrderByExpressions.Select(o => new OrderByExpression(fieldReplacer.Visit(o.Expression), o.Ascending)),
                    multiPartQuery.Count)
                    : new Query(
                    multiPartQuery.Fields.Where(f => f.SourceAlias == this.alias).Select(f => f.FieldName),
                    fieldReplacer.Visit(multiPartQuery.FilterExpression),
                    multiPartQuery.OrderByExpressions.Select(o => new OrderByExpression(fieldReplacer.Visit(o.Expression), o.Ascending)),
                    multiPartQuery.Count);

            var rowBuilder = new RowBuilder(this.alias);

            return(context
                   .CreateAsyncEnumerable(async() => (await this.selectPlan.ExecuteAsync(context)).QueryResults.First().Rows)
                   .Select(rowBuilder.Attach)
                   .Where(query.GetFilter(context)?.GetRowFilter())
                   .OrderBy(query.GetSortOrders(context)));
        }
Пример #3
0
        public IEnumerable <IOrderByExpression> GetSortOrders(IExecutionContext context)
        {
            var visitor = GenericVisitor.Create((ExecutionContextExpression e) => Expression.Constant(context));

            return(this.OrderByExpressions.Select(o => new OrderByExpression(visitor.Visit(o.Expression), o.Ascending)));
        }
Пример #4
0
        /// <summary>
        /// The get rows.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="multiPartQuery">
        /// The multi-part query.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncEnumerable{Row}"/>.
        /// </returns>
        internal override IAsyncEnumerable <Row> GetRows([NotNull] IInternalExecutionContext context, [NotNull] IMultiPartQuery multiPartQuery)
        {
            var functionName  = context.GetDisplayName(this.dataSource);
            var fieldReplacer = GenericVisitor.Create((SourceFieldExpression e) => CustomExpression.MakeField(e.SourceName, e.FieldName, e.Type));

            var query =
                multiPartQuery.WildcardAliases.Contains(this.alias) ?
                new Query(
                    fieldReplacer.Visit(multiPartQuery.FilterExpression),
                    multiPartQuery.OrderByExpressions.Select(o => new OrderByExpression(fieldReplacer.Visit(o.Expression), o.Ascending)),
                    multiPartQuery.Count)
                    : new Query(
                    multiPartQuery.Fields.Where(f => f.SourceAlias == this.alias).Select(f => f.FieldName),
                    fieldReplacer.Visit(multiPartQuery.FilterExpression),
                    multiPartQuery.OrderByExpressions.Select(o => new OrderByExpression(fieldReplacer.Visit(o.Expression), o.Ascending)),
                    multiPartQuery.Count);

            Expression unsupportedFilters = null;

            IOrderByExpression[] unsupportedOrderByExpressions = null;

            // ReSharper disable once SuspiciousTypeConversion.Global, implemented in other assemblies.
            var expressionSupport = this.dataSource as IDataSourceFilterSupport;

            if (expressionSupport != null)
            {
                var parts           = query.FilterExpression.SplitByAndExpressions().Cast <CompareExpression>().ToArray();
                var filters         = parts.ToLookup(p => expressionSupport.SupportsExpression(p), e => (Expression)e);
                var supportedFilter = filters[true].DefaultIfEmpty().Aggregate(Expression.AndAlso);

                unsupportedFilters = filters[false].DefaultIfEmpty().Aggregate(Expression.AndAlso);

                if (!query.RetrieveAllFields)
                {
                    query = new Query(query.Fields.Concat(unsupportedFilters.GetFields().Select(u => u.FieldName)).Distinct(), supportedFilter, query.OrderByExpressions, query.Count);
                }

                if (unsupportedFilters != null)
                {
                    context.Logger.Warning($"Data source {functionName} {this.alias} has unsupported filter {unsupportedFilters}. This could impact performance.");
                }
            }

            // ReSharper disable once SuspiciousTypeConversion.Global, implemented in other assemblies.
            var orderBySupport = this.dataSource as IDataSourceOrderBySupport;

            if (orderBySupport != null && !orderBySupport.SupportsOrderBy(query.OrderByExpressions))
            {
                unsupportedOrderByExpressions = query.OrderByExpressions.ToArray();

                if (!query.RetrieveAllFields)
                {
                    query = new Query(query.Fields.Concat(unsupportedOrderByExpressions.SelectMany(e => e.Expression.GetFields().Select(f => f.FieldName))).Distinct(), query.FilterExpression, null, query.Count);
                }

                context.Logger.Warning($"Data source  {functionName} {this.alias} has unsupported ORDER BY {string.Join(", ", unsupportedOrderByExpressions.Select(u => u.Expression + " " + (u.Ascending ? "ASC" : "DESC")))}. This could impact performance.");
            }

            var sourceName = functionName + (query.FilterExpression == null ? string.Empty : $" with query '{query.FilterExpression}'");

            context.Logger.Verbose($"Retrieving data from {sourceName}.");

            try
            {
                var result = this.dataSource.GetRows(context, new RowBuilder(this.alias), query).AfterLastElement(count => context.Logger.Verbose($"Retrieved {count} items from {sourceName}."));

                if (unsupportedFilters != null)
                {
                    result = result.Where(unsupportedFilters.GetRowFilter());
                }

                if (unsupportedOrderByExpressions != null)
                {
                    result.OrderBy(unsupportedOrderByExpressions);
                }

                return(result);
            }
            catch (Exception e)
            {
                context.Logger.Error($"An error occurred while querying {sourceName}: {e.Message}.");

                return(context.CreateEmptyAsyncEnumerable <Row>());
            }
        }