using System.Collections;
using System.Text;
using Strata.SqlTools.SqlBreakdown.Interfaces;
namespace Strata.SqlTools.SqlBreakdown.Classes;
///
/// Base class for SQL query breakdowns that provides common setup/finish clause handling and cloning.
///
public abstract class SqlBreakdownBase : ISqlBreakdown
{
///
/// Initializes a new instance of the class.
///
protected SqlBreakdownBase()
{
SetupClauses = [];
FinishClauses = [];
}
///
/// Gets or sets the setup clauses to execute before the main query.
///
public List SetupClauses { get; set; }
///
/// Gets a value indicating whether setup clauses are being used.
///
public bool IsUsingSetupClause => SetupClauses.Count > 0;
///
/// Gets or sets the raw/original SQL statement before parsing and breakdown.
///
///
/// This property stores the original SQL text that was parsed to create this breakdown.
/// It's useful for auditing, logging, and batch statement retrieval.
///
public string? RawSql { get; set; }
///
/// Gets or sets the finish clauses to execute after the main query.
///
public ArrayList FinishClauses { get; set; }
///
/// Gets a value indicating whether finish clauses are being used.
///
public bool IsUsingFinishClause => FinishClauses.Count > 0;
///
/// Gets the SQL breakdown as a string. Must be implemented by derived classes.
///
/// The SQL query string.
protected abstract string GetSqlBreakdown();
///
/// Appends a SQL fragment to an with the given logical operation
/// (e.g. "and" / "or"), and optionally merges an associated comment.
/// If the target clause is empty, the fragment is set as the clause; otherwise it is
/// joined with the operation.
///
/// The clause being built up (e.g. WhereClause, HavingClause).
/// The already-generated SQL fragment to append.
/// The logical operation used to join with the existing content.
/// Optional comment to merge into clause.Comment.
protected static void AppendToClause(ISqlClause clause, string sql, string operation, string? comment)
{
if (string.IsNullOrWhiteSpace(clause.Clause))
{
clause.Clause = sql;
}
else
{
clause.Clause = $"{clause.Clause} {operation} {sql}";
}
if (string.IsNullOrWhiteSpace(comment))
{
return;
}
if (string.IsNullOrWhiteSpace(clause.Comment))
{
clause.Comment = comment;
}
else
{
clause.Comment = $"{clause.Comment} {comment}";
}
}
///
/// Gets a LINQ to SQL query of the specified type based on this breakdown.
///
/// The entity type for the query.
/// An IQueryable of the specified type; an empty queryable if the breakdown cannot be converted to a LINQ query.
///
/// This method allows derived breakdown classes to reconstruct or generate LINQ queries
/// from the analyzed components (SELECT, WHERE, ORDER BY, etc.).
/// The default implementation returns an empty queryable.
///
public virtual IQueryable GetQuery() where T : class => Enumerable.Empty().AsQueryable();
///
/// Gets the complete SQL query including optional setup and finish clauses.
///
/// Whether to include setup and finish clauses.
/// The complete SQL query string.
public string GetSql(bool includeSetupFinish = true)
{
var sb = new StringBuilder();
if (includeSetupFinish)
{
// Write out any setup clauses
sb.AppendLine();
foreach (string setup in SetupClauses)
{
sb.AppendLine(setup);
}
sb.AppendLine();
}
sb.Append(GetSqlBreakdown());
if (includeSetupFinish)
{
// Write out any finish clauses
sb.AppendLine();
sb.AppendLine();
foreach (string finish in FinishClauses)
{
sb.AppendLine(finish);
}
}
return sb.ToString();
}
///
/// Returns the SQL query as a string.
///
/// The SQL query string.
public override string ToString()
=> GetSql();
///
/// Creates a deep clone of this object.
///
/// A cloned instance.
public object Clone()
{
// Create a shallow copy
var clone = (SqlBreakdownBase)MemberwiseClone();
// Deep copy the SetupClauses list
clone.SetupClauses = new List(SetupClauses);
// Deep copy the FinishClauses ArrayList
clone.FinishClauses = new ArrayList(FinishClauses);
return clone;
}
}