using System.Collections.Generic; using System.Runtime.CompilerServices; using AnalyticsBLL.AnalysisAggregation; using AnalyticsDAL.DTO.AnalysisAggregation.V1; using FastEndpoints; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using GB5Shared.DTO.Report; using GB5Shared.FastEndPoint; using static GB5Shared.GB5Constant.Constant; namespace AnalyticsSL.EndPoints.BI { /// The unified BI engine endpoint — resolves any of the three MBICATALOG dataset /// kinds (Warehouse/AnalysisQuery/ApiService) via IAnalysisAggregationService and returns /// the shaped AnalysisResult contract. /// /// Deliberately separate from the legacy AnalysisDynamicOutput.cs (AnalysisQueryId + /// ReportViewId params, flat JSON list response) — that endpoint's shipped contract stays /// untouched for existing consumers. This endpoint inherits BaseReportEndpoint so /// Excel/CSV/PDF/NDJSON export come for free via IReportExport, without duplicating any /// export plumbing. public class RunBIQuery : BaseReportEndpoint> { private readonly IAnalysisAggregationService _aggregationService; public RunBIQuery(IAnalysisAggregationService aggregationService) { _aggregationService = aggregationService; } public override void Configure() { Post("/BI/RunBIQuery"); AllowAnonymous(); } public record RunBIQueryParameters( [property: FromHeader] string Login, [property: FromBody] AnalysisQueryDefinition Definition ); // Export path — streams ALL rows (per BaseReportEndpoint contract, paging is ignored here). protected override async IAsyncEnumerable> ExecuteReportAsync( RunBIQueryParameters req, LoginDTO login, [EnumeratorCancellation] CancellationToken ct) { var result = await _aggregationService.ExecuteAsync(req.Definition, login, ct).ConfigureAwait(false); foreach (var row in result.Data) yield return row; } // Plain-JSON/UI-grid path — overridden (per BaseReportEndpoint's documented extension // point) to return the full AnalysisResult (meta + data), not just a capped flat list. protected override async Task> ExecutePagedAsync( RunBIQueryParameters req, LoginDTO login, CancellationToken ct) { var result = await _aggregationService.ExecuteAsync(req.Definition, login, ct).ConfigureAwait(false); // NOT_REQUIRED here — BLL-level IDALCache already caches the computed AnalysisResult // (AnalysisAggregationService §7); caching again at the SL response layer under a // different key scheme would double-cache the same result for no benefit. return await GB5Shared.ResponseStandard.Response.CreateSuccessResponse( result, CacheKeyLevel.NOT_REQUIRED, login); } // BaseReportEndpoint.HandleAsync requires a ReportCallingDTO on the request to trigger // export formats; RunBIQueryParameters intentionally has none (AnalysisQueryDefinition // is the sole FromBody payload, matching this module's one-FromBody-property convention — // see SaveAnalysis.cs/AnalysisDynamicOutput.cs). Synthesize a minimal one instead of adding // an export-specific field to the versioned analytics contract. protected override ReportCallingDTO? GetReportCallingDTOFromRequest(RunBIQueryParameters req) => new ReportCallingDTO { ReportTitle = "Analysis Result" }; } }