using Strata.SqlTools.SqlBreakdown.Interfaces.Core;
using Strata.SqlTools.SqlBreakdown.Expressions.Arithmetic;
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional.Comparisons;
using Strata.SqlTools.SqlBreakdown.Expressions.Literals;
namespace Strata.SqlTools.SqlBreakdown.Expressions;
///
/// Abstract base class for all SQL expression types. Provides operator overloading for
/// building complex SQL expressions using C# operators and implicit conversions for
/// common value types.
///
///
/// This class enables type-safe SQL expression building using familiar C# syntax.
/// Supports arithmetic operators (+, -, *, /), comparison operators (==, !=, >, <, >=, <=),
/// and implicit conversions from common .NET types. All derived expression classes
/// implement the visitor pattern through for SQL generation.
///
///
///
/// // Build expressions using operators
/// var price = new GenericColumnExpression("Price", "Products");
/// var discount = new GenericColumnExpression("Discount", "Products");
///
/// // Arithmetic operations
/// var discountedPrice = price * (1.0m - discount);
///
/// // Comparison operations
/// var affordableItems = price <= 100;
/// var expensiveItems = price > 1000;
///
/// // Implicit conversions from literals
/// Expression literalNumber = 42.5m;
/// Expression literalString = "Sample";
/// Expression literalDate = new DateTime(2024, 1, 1);
///
/// // Factory method for dynamic values
/// Expression valueFromObject = Expression.FromObject(someValue);
///
///
public abstract class Expression
{
///
/// Determines whether the specified object is equal to the current expression.
/// Uses reference equality since the == operator is overloaded for SQL expression building.
///
/// The object to compare with the current expression.
/// True if the specified object is the same instance; otherwise, false.
public override bool Equals(object? obj)
{
return ReferenceEquals(this, obj);
}
///
/// Returns the hash code for this expression instance.
/// Uses the base implementation for reference-based hashing.
///
/// A hash code for the current expression.
public override int GetHashCode()
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this);
}
///
/// Accepts a visitor for the visitor pattern, allowing different SQL generation
/// strategies.
///
/// The return type of the visitor.
///
/// The visitor instance that will process this expression.
///
/// The result from the visitor's processing of this expression.
public abstract T Accept(IVisitor visitor);
///
/// Creates an appropriate expression from a .NET object value. Automatically converts
/// common types to their corresponding literal expressions.
///
///
/// The object to convert. Supported types include numeric types (short, int, long,
/// double, decimal), bool, DateTime, DateOnly, DateTimeOffset, and string.
///
///
/// A literal expression representing the value. Returns
/// for null values.
///
///
///
/// // Numeric types become NumberLiteralExpression
/// var num = Expression.FromObject(42);
///
/// // Boolean values become BooleanLiteralExpression
/// var flag = Expression.FromObject(true);
///
/// // DateTime values become DateTimeLiteralExpression
/// var date = Expression.FromObject(DateTime.Now);
///
/// // Strings become StringLiteralExpression
/// var text = Expression.FromObject("example");
///
/// // Null becomes NullLiteralExpression
/// var nullValue = Expression.FromObject(null);
///
///
public static Expression FromObject(object? value)
{
return value switch
{
null => new NullLiteralExpression(),
short s => new NumberLiteralExpression(s),
int i => new NumberLiteralExpression(i),
long l => new NumberLiteralExpression(l),
double d => new NumberLiteralExpression((decimal)d),
decimal m => new NumberLiteralExpression(m),
bool b => new BooleanLiteralExpression(b),
DateOnly d => new DateTimeLiteralExpression(d.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc)),
DateTime dt => new DateTimeLiteralExpression(dt),
DateTimeOffset dto => new DateTimeLiteralExpression(dto.UtcDateTime),
string s when DateTime.TryParse(s, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out var dt) => new DateTimeLiteralExpression(dt),
_ when value.ToString() == null => new NullLiteralExpression(),
_ => new StringLiteralExpression(value.ToString()!)
};
}
#region Literal Value Implicit Operators
///
/// Implicitly converts a decimal number to a
/// .
///
/// The numeric value.
public static implicit operator Expression(decimal number) => new NumberLiteralExpression(number);
///
/// Implicitly converts a string to a .
///
/// The string value.
public static implicit operator Expression(string value) => new StringLiteralExpression(value);
///
/// Implicitly converts a DateTime to a .
///
/// The DateTime value.
public static implicit operator Expression(DateTime dateTime) => new DateTimeLiteralExpression(dateTime);
///
/// Implicitly converts a DateOnly to a .
///
/// The DateOnly value.
public static implicit operator Expression(DateOnly date) => new DateTimeLiteralExpression(date.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc));
#endregion
#region Comparison Operators
///
/// Creates an equality comparison expression (=).
///
/// The left expression.
/// The right expression.
/// An .
public static ComparisonOperatorExpression operator ==(Expression a, Expression b) => new EqualToExpression(a, b);
///
/// Creates an inequality comparison expression (!=).
///
/// The left expression.
/// The right expression.
/// A .
public static ComparisonOperatorExpression operator !=(Expression a, Expression b) => new NotEqualToExpression(a, b);
///
/// Creates a greater-than comparison expression (>).
///
/// The left expression.
/// The right expression.
/// A .
public static ComparisonOperatorExpression operator >(Expression a, Expression b) => new GreaterThanExpression(a, b);
///
/// Creates a less-than comparison expression (<).
///
/// The left expression.
/// The right expression.
/// A .
public static ComparisonOperatorExpression operator <(Expression a, Expression b) => new LessThanExpression(a, b);
///
/// Creates a greater-than-or-equal comparison expression (>=).
///
/// The left expression.
/// The right expression.
/// A .
public static ComparisonOperatorExpression operator >=(Expression a, Expression b) => new GreaterThanOrEqualToExpression(a, b);
///
/// Creates a less-than-or-equal comparison expression (<=).
///
/// The left expression.
/// The right expression.
/// A .
public static ComparisonOperatorExpression operator <=(Expression a, Expression b) => new LessThanOrEqualToExpression(a, b);
#endregion
#region Arithmetic Operators
///
/// Creates an addition expression (+).
///
/// The left expression.
/// The right expression.
/// An .
public static ArithmeticExpression operator +(Expression a, Expression b) => new AdditionExpression(a, b);
///
/// Creates a subtraction expression (-).
///
/// The left expression.
/// The right expression.
/// A .
public static ArithmeticExpression operator -(Expression a, Expression b) => new SubtractionExpression(a, b);
///
/// Creates a multiplication expression (*).
///
/// The left expression.
/// The right expression.
/// A .
public static ArithmeticExpression operator *(Expression a, Expression b) => new MultiplicationExpression(a, b);
///
/// Creates a division expression (/).
///
/// The left expression.
/// The right expression.
/// A .
public static ArithmeticExpression operator /(Expression a, Expression b) => new DivisionExpression(a, b);
#endregion
}