chore: initial git load of code space
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Strata.SqlTools.SqlBreakdown.Classes;
|
||||
using Strata.SqlTools.Statements.SqlServer;
|
||||
|
||||
namespace Strata.SqlTools.Breakdowns.SqlServer;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an UPDATE SQL statement breakdown with SET, FROM, and WHERE clauses for SQL Server.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UpdateBreakdown : SqlBreakdownBase
|
||||
{
|
||||
protected readonly StatementParser Parser;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UpdateBreakdown"/> class.
|
||||
/// </summary>
|
||||
public UpdateBreakdown()
|
||||
{
|
||||
Parser = new StatementParser();
|
||||
TableName = new SqlClause();
|
||||
SetClause = new SqlClause();
|
||||
FromClause = new SqlClause();
|
||||
WhereClause = new SqlClause();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UpdateBreakdown"/> class.
|
||||
/// </summary>
|
||||
/// <param name="tableName">The table name.</param>
|
||||
/// <param name="setClause">The SET clause.</param>
|
||||
/// <param name="whereClause">The WHERE clause.</param>
|
||||
public UpdateBreakdown(string tableName, string setClause, string whereClause) : this()
|
||||
{
|
||||
var cleanTable = Parser.ExtractSqlComments(tableName, out var tableComments);
|
||||
TableName.Clause = cleanTable.Trim();
|
||||
TableName.Comment = tableComments.Count > 0 ? string.Join(" ", tableComments) : null;
|
||||
|
||||
var cleanSet = Parser.ExtractSqlComments(setClause, out var setComments);
|
||||
SetClause.Clause = cleanSet.Trim();
|
||||
SetClause.Comment = setComments.Count > 0 ? string.Join(" ", setComments) : null;
|
||||
|
||||
var cleanWhere = Parser.ExtractSqlComments(whereClause, out var whereComments);
|
||||
WhereClause.Clause = cleanWhere.Trim();
|
||||
WhereClause.Comment = whereComments.Count > 0 ? string.Join(" ", whereComments) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the SET clause.
|
||||
/// </summary>
|
||||
public SqlClause SetClause { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the table name.
|
||||
/// </summary>
|
||||
public SqlClause TableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a FROM clause is being used.
|
||||
/// </summary>
|
||||
public bool IsUsingFromClause => !string.IsNullOrWhiteSpace(FromClause.Clause);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the FROM clause (for UPDATE with JOIN).
|
||||
/// </summary>
|
||||
public SqlClause FromClause { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a WHERE clause is being used.
|
||||
/// </summary>
|
||||
public bool IsUsingWhereClause => !string.IsNullOrWhiteSpace(WhereClause.Clause);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the WHERE clause.
|
||||
/// </summary>
|
||||
public SqlClause WhereClause { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SQL breakdown as a string.
|
||||
/// </summary>
|
||||
/// <returns>The UPDATE SQL statement.</returns>
|
||||
protected override string GetSqlBreakdown()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine("UPDATE ");
|
||||
sb.AppendLine($" {TableName.Clause}");
|
||||
|
||||
sb.AppendLine("SET ");
|
||||
sb.AppendLine($" {SetClause.Clause}");
|
||||
|
||||
if (IsUsingFromClause)
|
||||
{
|
||||
sb.AppendLine("FROM ");
|
||||
sb.AppendLine($" {FromClause.Clause}");
|
||||
}
|
||||
|
||||
if (IsUsingWhereClause)
|
||||
{
|
||||
sb.AppendLine("WHERE ");
|
||||
sb.AppendLine($" {WhereClause.Clause}");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
#region Parse Methods
|
||||
|
||||
/// <summary>
|
||||
/// Parses an UPDATE SQL statement into an UpdateBreakdown object.
|
||||
/// </summary>
|
||||
/// <param name="sql">The UPDATE SQL statement to parse.</param>
|
||||
/// <returns>An UpdateBreakdown object representing the parsed statement.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when sql is null or empty.</exception>
|
||||
/// <exception cref="FormatException">Thrown when the SQL statement cannot be parsed.</exception>
|
||||
public static UpdateBreakdown Parse(string sql)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(sql))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(sql), "SQL statement cannot be null or empty.");
|
||||
}
|
||||
|
||||
if (!TryParse(sql, out var result, out var error))
|
||||
{
|
||||
throw new FormatException($"Failed to parse UPDATE statement: {error}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to parse an UPDATE SQL statement into an UpdateBreakdown object.
|
||||
/// </summary>
|
||||
/// <param name="sql">The UPDATE SQL statement to parse.</param>
|
||||
/// <param name="result">When this method returns, contains the parsed UpdateBreakdown if successful, or null if parsing failed.</param>
|
||||
/// <returns>true if the SQL was successfully parsed; otherwise, false.</returns>
|
||||
public static bool TryParse(string sql, out UpdateBreakdown result)
|
||||
=> TryParse(sql, out result, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to parse an UPDATE SQL statement into an UpdateBreakdown object.
|
||||
/// </summary>
|
||||
/// <param name="sql">The UPDATE SQL statement to parse.</param>
|
||||
/// <param name="result">When this method returns, contains the parsed UpdateBreakdown if successful, or null if parsing failed.</param>
|
||||
/// <param name="errorMessage">When this method returns false, contains a message describing why parsing failed.</param>
|
||||
/// <returns>true if the SQL was successfully parsed; otherwise, false.</returns>
|
||||
public static bool TryParse(string sql, out UpdateBreakdown result, out string errorMessage)
|
||||
{
|
||||
result = null!;
|
||||
errorMessage = null!;
|
||||
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(sql))
|
||||
{
|
||||
errorMessage = "SQL statement cannot be null or empty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
var parser = new StatementParser();
|
||||
sql = parser.NormalizeSqlPreservingComments(sql);
|
||||
|
||||
// Check if it's an UPDATE statement
|
||||
var sqlTrimmed = sql.TrimStart();
|
||||
if (!Regex.IsMatch(sqlTrimmed, @"^\s*UPDATE\b",
|
||||
RegexOptions.IgnoreCase))
|
||||
{
|
||||
errorMessage = "SQL statement must start with UPDATE.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract setup and finish clauses
|
||||
var setupClauses = new List<string>();
|
||||
sql = parser.ExtractSetupClauses(sql, setupClauses);
|
||||
|
||||
var finishClauses = new ArrayList();
|
||||
sql = parser.ExtractFinishClauses(sql, finishClauses);
|
||||
|
||||
// Parse UPDATE statement - handle both with and without FROM clause
|
||||
// Pattern: UPDATE table SET column=value [FROM table] [WHERE condition]
|
||||
var updateMatch = Regex.Match(sql,
|
||||
@"UPDATE\s+([^\s]+)\s+SET\s+(.*?)(?:\s+FROM\s+(.*?))?(?:\s+WHERE\s+(.*))?$",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
|
||||
if (!updateMatch.Success)
|
||||
{
|
||||
errorMessage = "Could not parse UPDATE statement. Expected format: UPDATE table SET column=value [FROM table] [WHERE condition]";
|
||||
return false;
|
||||
}
|
||||
|
||||
var tableName = updateMatch.Groups[1].Value.Trim();
|
||||
var setClause = updateMatch.Groups[2].Value.Trim();
|
||||
var fromClause = updateMatch.Groups.Count > 3 ? updateMatch.Groups[3].Value.Trim() : string.Empty;
|
||||
var whereClause = updateMatch.Groups.Count > 4 ? updateMatch.Groups[4].Value.Trim() : string.Empty;
|
||||
|
||||
result = new UpdateBreakdown(tableName, setClause, whereClause)
|
||||
{
|
||||
SetupClauses = setupClauses,
|
||||
FinishClauses = finishClauses
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(fromClause))
|
||||
{
|
||||
var cleanFrom = parser.ExtractSqlComments(fromClause, out var fromComments);
|
||||
result.FromClause.Clause = cleanFrom.Trim();
|
||||
result.FromClause.Comment = fromComments.Count > 0 ? string.Join(" ", fromComments) : null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"Unexpected error during parsing: {ex.Message}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user