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 }