Files
sql-utilities/src/Strata.SqlTools.LinqToSql/Builders/LinqQueryBreakdownBuilder.cs
T

232 lines
7.0 KiB
C#

using Strata.SqlTools.Breakdowns.LinqToSql;
namespace Strata.SqlTools.Builders.LinqToSql;
/// <summary>
/// Fluent builder for constructing LinqQueryBreakdown instances programmatically.
/// Useful for scenarios where you don't have a live IQueryable to analyze.
/// </summary>
public class LinqQueryBreakdownBuilder
{
private readonly LinqQueryBreakdown _breakdown;
private readonly List<string> _selectColumns = new();
private string? _fromTable;
private string? _whereClause;
private string? _groupByClause;
private string? _havingClause;
private string? _orderByClause;
/// <summary>
/// Initializes a new instance of the <see cref="LinqQueryBreakdownBuilder"/> class.
/// </summary>
public LinqQueryBreakdownBuilder()
{
_breakdown = new LinqQueryBreakdown();
}
/// <summary>
/// Sets the SELECT columns for the query.
/// </summary>
/// <param name="columns">Column names to select.</param>
/// <returns>This builder for method chaining.</returns>
public LinqQueryBreakdownBuilder SelectColumns(params string[] columns)
{
if (columns.Length == 0)
{
_selectColumns.Add("*");
}
else
{
_selectColumns.AddRange(columns);
}
return this;
}
/// <summary>
/// Sets the SELECT to all columns (*).
/// </summary>
/// <returns>This builder for method chaining.</returns>
public LinqQueryBreakdownBuilder SelectAll()
{
_selectColumns.Clear();
_selectColumns.Add("*");
return this;
}
/// <summary>
/// Sets the FROM table for the query.
/// </summary>
/// <param name="tableName">The table name.</param>
/// <returns>This builder for method chaining.</returns>
public LinqQueryBreakdownBuilder FromTable(string tableName)
{
if (string.IsNullOrWhiteSpace(tableName))
{
throw new ArgumentException("Table name cannot be null or empty.", nameof(tableName));
}
_fromTable = tableName;
return this;
}
/// <summary>
/// Sets the WHERE clause for the query.
/// </summary>
/// <param name="condition">The WHERE condition.</param>
/// <returns>This builder for method chaining.</returns>
public LinqQueryBreakdownBuilder Where(string condition)
{
if (!string.IsNullOrWhiteSpace(condition))
{
_whereClause = condition;
}
return this;
}
/// <summary>
/// Sets the GROUP BY clause for the query.
/// </summary>
/// <param name="columns">The columns to group by.</param>
/// <returns>This builder for method chaining.</returns>
public LinqQueryBreakdownBuilder GroupBy(params string[] columns)
{
if (columns.Length > 0)
{
_groupByClause = string.Join(", ", columns);
}
return this;
}
/// <summary>
/// Sets the HAVING clause for the query.
/// </summary>
/// <param name="condition">The HAVING condition.</param>
/// <returns>This builder for method chaining.</returns>
public LinqQueryBreakdownBuilder Having(string condition)
{
if (!string.IsNullOrWhiteSpace(condition))
{
_havingClause = condition;
}
return this;
}
/// <summary>
/// Sets the ORDER BY clause for the query.
/// </summary>
/// <param name="orderSpecification">The ORDER BY specification (e.g., "Name ASC, Age DESC").</param>
/// <returns>This builder for method chaining.</returns>
public LinqQueryBreakdownBuilder OrderBy(string orderSpecification)
{
if (!string.IsNullOrWhiteSpace(orderSpecification))
{
_orderByClause = orderSpecification;
}
return this;
}
/// <summary>
/// Adds an ORDER BY clause in ascending order.
/// </summary>
/// <param name="column">The column to order by.</param>
/// <returns>This builder for method chaining.</returns>
public LinqQueryBreakdownBuilder OrderByAscending(string column)
{
if (string.IsNullOrWhiteSpace(column))
{
throw new ArgumentException("Column name cannot be null or empty.", nameof(column));
}
_orderByClause = $"{column} ASC";
return this;
}
/// <summary>
/// Adds an ORDER BY clause in descending order.
/// </summary>
/// <param name="column">The column to order by.</param>
/// <returns>This builder for method chaining.</returns>
public LinqQueryBreakdownBuilder OrderByDescending(string column)
{
if (string.IsNullOrWhiteSpace(column))
{
throw new ArgumentException("Column name cannot be null or empty.", nameof(column));
}
_orderByClause = $"{column} DESC";
return this;
}
/// <summary>
/// Builds and returns the LinqQueryBreakdown instance.
/// </summary>
/// <returns>A new LinqQueryBreakdown with the configured clauses.</returns>
/// <exception cref="InvalidOperationException">Thrown when required clauses are missing.</exception>
public LinqQueryBreakdown Build()
{
if (_selectColumns.Count == 0)
{
throw new InvalidOperationException("At least one SELECT column must be specified.");
}
if (string.IsNullOrWhiteSpace(_fromTable))
{
throw new InvalidOperationException("FROM table must be specified.");
}
var breakdown = new LinqQueryBreakdown(
string.Join(", ", _selectColumns),
_fromTable,
_whereClause ?? string.Empty
);
if (!string.IsNullOrWhiteSpace(_groupByClause))
{
breakdown.GroupByClause.Clause = _groupByClause;
}
if (!string.IsNullOrWhiteSpace(_havingClause))
{
breakdown.HavingClause.Clause = _havingClause;
}
if (!string.IsNullOrWhiteSpace(_orderByClause))
{
breakdown.OrderByClause.Clause = _orderByClause;
}
return breakdown;
}
/// <summary>
/// Gets a SQL Server formatted preview of the query being built.
/// </summary>
/// <returns>Preview SQL statement.</returns>
public string PreviewSql()
{
try
{
return Build().ToSqlServerSql();
}
catch (InvalidOperationException)
{
return "-- Incomplete query (missing required clauses)";
}
}
/// <summary>
/// Creates a new builder with the default state.
/// </summary>
/// <returns>A new LinqQueryBreakdownBuilder instance.</returns>
public static LinqQueryBreakdownBuilder Create()
{
return new LinqQueryBreakdownBuilder();
}
/// <summary>
/// Creates a builder with a table already specified.
/// </summary>
/// <param name="tableName">The table to select from.</param>
/// <returns>A new builder with the table set.</returns>
public static LinqQueryBreakdownBuilder CreateForTable(string tableName)
{
return new LinqQueryBreakdownBuilder().FromTable(tableName);
}
}