using Strata.SqlTools.SqlBreakdown.Classes; using Strata.SqlTools.SqlBreakdown.Interfaces; namespace Strata.SqlTools.Breakdowns.SqlServer; /// /// Base collection that manages a strongly typed list of query breakdowns and provides the /// dialect-agnostic plumbing, filters, and analysis shared by the per-dialect collections. /// /// The concrete query breakdown type held by the collection. /// /// Each dialect collection closes the generic over its own query type (for example, /// QueryBreakdownCollectionBase<Snowflake.QueryBreakdown>) so that public members such as /// and the Where* filters keep their dialect-specific element type. /// public abstract class QueryBreakdownCollectionBase : SqlBreakdownCollection where TQuery : QueryBreakdown { /// /// Gets the backing list of typed query breakdowns. /// protected List QueryBreakdownList { get; } /// /// Initializes a new, empty instance. /// protected QueryBreakdownCollectionBase() : base() { QueryBreakdownList = new List(); } /// /// Initializes a new instance with initial query breakdowns. /// /// The initial collection of query breakdowns. protected QueryBreakdownCollectionBase(IEnumerable queryBreakdowns) : base(queryBreakdowns?.Cast() ?? Enumerable.Empty()) { QueryBreakdownList = new List(queryBreakdowns ?? Enumerable.Empty()); } /// /// Gets the collection of query breakdowns. /// public IReadOnlyList QueryBreakdowns => QueryBreakdownList.AsReadOnly(); /// /// Adds a query breakdown to the collection. /// /// The query breakdown to add. /// Thrown when is null. public void Add(TQuery queryBreakdown) { ArgumentNullException.ThrowIfNull(queryBreakdown); QueryBreakdownList.Add(queryBreakdown); base.Add(queryBreakdown); } /// /// Adds multiple query breakdowns to the collection. /// /// The query breakdowns to add. /// Thrown when is null. public void AddRange(IEnumerable queryBreakdowns) { ArgumentNullException.ThrowIfNull(queryBreakdowns); foreach (var breakdown in queryBreakdowns) { Add(breakdown); } } /// /// Removes a query breakdown from the collection. /// /// The query breakdown to remove. /// True if removed; otherwise, false. public bool Remove(TQuery queryBreakdown) { var removed = QueryBreakdownList.Remove(queryBreakdown); if (removed) { base.Remove(queryBreakdown); } return removed; } /// /// Clears all query breakdowns from the collection. /// public new void Clear() { QueryBreakdownList.Clear(); base.Clear(); } /// /// Filters query breakdowns where the SELECT clause contains specific text. /// /// The text to find in the SELECT clause. /// Filtered query breakdowns. public IEnumerable WhereSelectContains(string selectContains) { if (string.IsNullOrWhiteSpace(selectContains)) { throw new ArgumentNullException(nameof(selectContains)); } return QueryBreakdownList.Where(q => q.SelectClause?.Clause?.Contains(selectContains, StringComparison.OrdinalIgnoreCase) ?? false); } /// /// Filters query breakdowns where the FROM clause contains specific text. /// /// The table name or pattern to find. /// Filtered query breakdowns. public IEnumerable WhereTableContains(string tableNameContains) { if (string.IsNullOrWhiteSpace(tableNameContains)) { throw new ArgumentNullException(nameof(tableNameContains)); } return QueryBreakdownList.Where(q => q.FromClause?.Clause?.Contains(tableNameContains, StringComparison.OrdinalIgnoreCase) ?? false); } /// /// Filters query breakdowns that have a WHERE clause. /// /// Query breakdowns with WHERE clauses. public IEnumerable WhereHaveWhereClause() { return QueryBreakdownList.Where(q => !string.IsNullOrWhiteSpace(q.WhereClause?.Clause)); } /// /// Filters query breakdowns that do NOT have a WHERE clause. /// /// /// This is useful for identifying potentially risky queries that affect all rows. /// /// Query breakdowns without WHERE clauses. public IEnumerable WhereHaveNoWhereClause() { return QueryBreakdownList.Where(q => string.IsNullOrWhiteSpace(q.WhereClause?.Clause)); } /// /// Filters query breakdowns that have a GROUP BY clause. /// /// Query breakdowns with GROUP BY clauses. public IEnumerable WhereHaveGroupByClause() { return QueryBreakdownList.Where(q => !string.IsNullOrWhiteSpace(q.GroupByClause?.Clause)); } /// /// Filters query breakdowns that have an ORDER BY clause. /// /// Query breakdowns with ORDER BY clauses. public IEnumerable WhereHaveOrderByClause() { return QueryBreakdownList.Where(q => !string.IsNullOrWhiteSpace(q.OrderByClause?.Clause)); } /// /// Gets the total number of columns selected across all queries. /// /// Total column count. public int GetTotalSelectedColumns() => QueryCollectionAnalysisHelper.GetTotalSelectedColumns(QueryBreakdownList); /// /// Gets all unique table names referenced across all queries. /// /// /// This provides a quick overview of which tables are being queried. /// Note: This is a best-effort extraction and may not capture all table references, /// especially in complex subqueries or with aliasing. /// /// List of unique table names. public IEnumerable GetUniqueTableReferences() => QueryCollectionAnalysisHelper.GetUniqueTableReferences(QueryBreakdownList); /// /// Synchronizes parameter values across all queries in the collection. /// /// /// Ensures all queries share the same parameter value based on parameter name. Later parameter /// values override earlier ones if there are conflicts. Only parameters a query already defines /// are synchronized, to avoid adding unused parameters. /// public void SynchronizeParameters() => QueryCollectionAnalysisHelper.SynchronizeParameters(QueryBreakdownList); /// /// Gets all unique parameters from all queries in the collection as a combined dictionary. /// /// A dictionary containing all unique parameters across all queries. protected Dictionary GetCombinedParameterDictionary() => QueryCollectionAnalysisHelper.GetCombinedParameters(QueryBreakdownList); }