// ============================================================================= // GB5 Framework — ReportExecutionContext // Namespace : GB5Shared.DTO.ReportOrchestration // Purpose : The single DTO that flows through the entire orchestration // pipeline. Carries identity, request parameters, resolved // datasource, execution decisions, and result metadata. // Created by QueryOrchestrator; read by all downstream layers. // ============================================================================= using GB5Shared.DTO.Framework.Login; using GB5Shared.Enums.ReportOrchestration; namespace GB5Shared.DTO.ReportOrchestration { /// /// Central context object for a single report execution request. /// Instantiated by and threaded through /// connection resolution, execution, pivot, and export stages. /// Immutable after construction except for fields set by the orchestrator /// during pipeline stages (ResolvedDataSource, IsAsync, JobId, etc.). /// public sealed class ReportExecutionContext { // --------------------------------------------------------------------- // IDENTITY — who is requesting, for which report // --------------------------------------------------------------------- /// /// The authenticated session. Source of ClientId, UserId, RoleId, /// ServerConfigId, DatabaseType, WorkDate, PeriodFromDate/ToDate. /// Never null; set at construction. /// public LoginDTO LoginDTO { get; init; } = null!; /// /// The MREPORT.REPORTID being executed. /// -1 for analysis reports (use AnalysisId instead). /// public int ReportId { get; init; } = -1; /// /// The MANALYSIS.ANALYSISID being executed. /// -1 for standard reports (use ReportId instead). /// public int AnalysisId { get; init; } = -1; /// /// The specific MREPORTVIEW.REPORTVIEWID requested. /// -1 means use the default view (ISDEFAULTVIEW = 0). /// public int ReportViewId { get; init; } = -1; /// /// Discriminates the call path so the orchestrator applies the /// correct resolution, execution, and export strategy. /// public ReportCallType CallType { get; init; } = ReportCallType.StandardReport; // --------------------------------------------------------------------- // REQUEST PARAMETERS — passed through to the module endpoint // --------------------------------------------------------------------- /// /// Report-specific filter parameters (date range, dimension filters, /// free-text search etc.) as key-value pairs. /// Forwarded as-is to the module endpoint via the HTTP request body. /// The orchestrator reads FromDate / ToDate for async decisions. /// public Dictionary Parameters { get; init; } = new(); /// /// Requested export format. Validated against /// MREPORTCONFIG.ALLOWEDEXPORTFORMATS before execution. /// public ExportFormat RequestedFormat { get; init; } = ExportFormat.Grid; /// /// Convenience: FromDate extracted from Parameters["FromDate"]. /// Used for period-based async threshold calculation. /// Null when not present or not applicable. /// public DateTime? FromDate { get; init; } /// /// Convenience: ToDate extracted from Parameters["ToDate"]. /// Used for period-based async threshold calculation. /// Null when not present or not applicable. /// public DateTime? ToDate { get; init; } /// /// Date range in days between FromDate and ToDate. /// Returns 0 when either date is absent. /// Used by AsyncMode.Auto threshold evaluation. /// public int DateRangeDays => (FromDate.HasValue && ToDate.HasValue) ? Math.Max(0, (int)(ToDate.Value.Date - FromDate.Value.Date).TotalDays) : 0; // --------------------------------------------------------------------- // RESOLVED CONFIGURATION — set by orchestrator after loading MREPORTCONFIG // --------------------------------------------------------------------- /// /// The MREPORTCONFIG loaded for this report. /// Null for analysis reports or when config is not yet loaded. /// public ReportConfigDTO? ReportConfig { get; set; } /// /// The final resolved DataSourceType after applying /// MREPORTCONFIG.DATASOURCETYPE and any matching MREPORTDATASOURCERULE. /// Set by the orchestrator's source resolution stage. /// public DataSourceType ResolvedDataSource { get; set; } = DataSourceType.Oltp; /// /// The resolved server configuration for the chosen DataSourceType. /// Set by . /// Contains the connection string and provider type — never serialised. /// public ReportServerConfigDTO? ResolvedServerConfig { get; set; } // --------------------------------------------------------------------- // EXECUTION DECISIONS — set by orchestrator before execution // --------------------------------------------------------------------- /// /// True when this request will be executed asynchronously via SysJob. /// Determined by AsyncMode + DateRangeDays + policy evaluation. /// public bool IsAsync { get; set; } /// /// The SysJob SYSJOBID submitted for async execution. /// -1 when IsAsync = false or before SysJob submission. /// public int SysJobId { get; set; } = -1; /// /// Query execution timeout in seconds. /// Sourced from MREPORTCONFIG.QUERYTIMEOUTSECONDS. /// Sync default: 30s. Async default: 300s. /// public int QueryTimeoutSeconds { get; set; } = 30; /// /// When true and DataSource is ReportDB or ArchiveDB on SQL Server, /// the orchestrator appends NOLOCK hints via query wrapper. /// Sourced from MREPORTCONFIG.ISNOLOCKALLOWED. /// Always false for OLTP writes and Oracle/PostgreSQL. /// public bool ApplyNoLock { get; set; } /// /// CancellationToken propagated from the HTTP request through the /// full execution pipeline (connection open, query, export). /// Allows browser-cancel to abort long-running queries. /// public CancellationToken CancellationToken { get; init; } = CancellationToken.None; // --------------------------------------------------------------------- // TRACING — for diagnostics and audit // --------------------------------------------------------------------- /// /// Unique identifier for this execution request. /// Used to correlate log entries across all pipeline stages. /// public Guid CorrelationId { get; init; } = Guid.NewGuid(); /// /// UTC timestamp when this context was created (request received). /// public DateTime RequestedAtUtc { get; init; } = DateTime.UtcNow; } // ========================================================================= // ReportConfigDTO — subset of MREPORTCONFIG columns loaded by orchestrator // ========================================================================= /// /// Projection of MREPORTCONFIG loaded by the orchestrator. /// Only the fields needed for execution decisions are included. /// Full MREPORTCONFIG entity lives in the DAL layer. /// public sealed class ReportConfigDTO { public int ReportConfigId { get; init; } public int ReportId { get; init; } /// Configured datasource preference before rule evaluation. public DataSourceType DataSourceType { get; init; } = DataSourceType.Oltp; /// Controls sync vs async execution decision. public AsyncMode AsyncMode { get; init; } = AsyncMode.Auto; /// /// When AsyncMode = Auto, requests with DateRangeDays exceeding this /// threshold are submitted as SysJob. Default: 90 days. /// public int AsyncThresholdDays { get; init; } = 90; /// Sync query timeout in seconds. Default: 30. public int QueryTimeoutSeconds { get; init; } = 30; /// Async (SysJob) query timeout in seconds. Default: 300. public int AsyncQueryTimeoutSeconds { get; init; } = 300; /// /// Minutes to cache the result. 0 = no cache. /// Cache key includes ReportId + CacheKeyParams + ClientId. /// public int CacheDurationMinutes { get; init; } /// /// Comma-separated parameter names that form part of the cache key. /// Null = all parameters included in cache key. /// public string? CacheKeyParams { get; init; } /// Default export format for this report. public ExportFormat DefaultExportFormat { get; init; } = ExportFormat.Grid; /// /// Comma-separated ExportFormat byte values that are allowed. /// e.g. "0,1,2" = Grid, PDF, Excel only. /// public string AllowedExportFormats { get; init; } = "0,1,2,3"; /// Where pivot transformation occurs. public PivotEngine PivotEngine { get; init; } = PivotEngine.None; /// Semantic category for UI grouping and default suggestions. public ReportCategory ReportCategory { get; init; } = ReportCategory.Operational; /// /// Whether NOLOCK hints may be applied when routing to ReportDB/ArchiveDB. /// Only honoured on SQL Server. False for Oracle/PostgreSQL. /// public bool IsNoLockAllowed { get; init; } /// SysJob result file TTL in hours. Default: 24. public int ResultExpiryHours { get; init; } = 24; /// SysJob priority (1–10). Higher = executed first. public byte DefaultPriority { get; init; } = 5; /// /// Optional COUNT query used by RuleType=1 (EstimatedRows) to decide /// whether to route to ReportDB or ArchiveDB. Null means no estimation query configured. /// public string? EstimationQuery { get; init; } } }