/// <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)); }
/// <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))); }
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))); }
/// <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>()); } }