using System.Collections.Generic; using GB5Shared.DTO.Framework.Criteria; namespace AnalyticsDAL.DTO.AnalysisAggregation.V1 { /// The versioned shaped-data request contract every analytics consumer (pivot, /// chart, export, snapshot) builds and re-submits to IAnalysisAggregationService. /// See the plan's "How slice/dice/drill-down actually works" section — every interaction /// (filter, re-pivot, drill) is a frontend concern that produces a new instance of this /// class and calls RunBIQuery again; there is no server-side session/cursor state. public class AnalysisQueryDefinition { public const string SchemaVersion = "1.1"; /// Resolves through MBICATALOG.BICATALOGID via IDatasetResolver. public int DatasetId { get; set; } public List Dimensions { get; set; } = new(); public List Measures { get; set; } = new(); public List Filters { get; set; } = new(); /// Result field names of MBIFIELDMAPPING.MAPPEDAS=2 (Computed) rows to evaluate /// after the dataset resolver returns. Deliberately a THIRD list, not entries in /// Dimensions/Measures: both of those are validated against the physical registry /// (ValidateAdditivity + WarehouseDAL.ResolveDimensionColumn/measuresByColumn) and would /// reject a computed field's name outright. Every source field a computed expression /// references must ALSO appear in Dimensions/Measures — see /// AnalysisAggregationService.ApplyComputedFieldsAsync — a computed field can never /// silently pull in an unselected/unaggregated measure. Additive and default-empty, so /// every existing MBIVIEW.BIDEFINITIONJSON row deserializes unchanged. public List ComputedFields { get; set; } = new(); /// Pivot placement — which Dimensions[].Field values are currently rows vs columns. public List Rows { get; set; } = new(); public List Columns { get; set; } = new(); /// Ordered hierarchy levels drilled so far (e.g. ["Year","Quarter","Month"]). public List DrillPath { get; set; } = new(); public List Sort { get; set; } = new(); public int? TopN { get; set; } } }