239 lines
10 KiB
C#
239 lines
10 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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 <see cref="Accept{T}"/> for SQL generation.
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code language="csharp">
|
|
/// // 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);
|
|
/// </code>
|
|
/// </example>
|
|
public abstract class Expression
|
|
{
|
|
/// <summary>
|
|
/// Determines whether the specified object is equal to the current expression.
|
|
/// Uses reference equality since the == operator is overloaded for SQL expression building.
|
|
/// </summary>
|
|
/// <param name="obj">The object to compare with the current expression.</param>
|
|
/// <returns>True if the specified object is the same instance; otherwise, false.</returns>
|
|
public override bool Equals(object? obj)
|
|
{
|
|
return ReferenceEquals(this, obj);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the hash code for this expression instance.
|
|
/// Uses the base implementation for reference-based hashing.
|
|
/// </summary>
|
|
/// <returns>A hash code for the current expression.</returns>
|
|
public override int GetHashCode()
|
|
{
|
|
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Accepts a visitor for the visitor pattern, allowing different SQL generation
|
|
/// strategies.
|
|
/// </summary>
|
|
/// <typeparam name="T">The return type of the visitor.</typeparam>
|
|
/// <param name="visitor">
|
|
/// The visitor instance that will process this expression.
|
|
/// </param>
|
|
/// <returns>The result from the visitor's processing of this expression.</returns>
|
|
public abstract T Accept<T>(IVisitor<T> visitor);
|
|
|
|
/// <summary>
|
|
/// Creates an appropriate expression from a .NET object value. Automatically converts
|
|
/// common types to their corresponding literal expressions.
|
|
/// </summary>
|
|
/// <param name="value">
|
|
/// The object to convert. Supported types include numeric types (short, int, long,
|
|
/// double, decimal), bool, DateTime, DateOnly, DateTimeOffset, and string.
|
|
/// </param>
|
|
/// <returns>
|
|
/// A literal expression representing the value. Returns
|
|
/// <see cref="NullLiteralExpression"/> for null values.
|
|
/// </returns>
|
|
/// <example>
|
|
/// <code language="csharp">
|
|
/// // 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);
|
|
/// </code>
|
|
/// </example>
|
|
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
|
|
/// <summary>
|
|
/// Implicitly converts a decimal number to a
|
|
/// <see cref="NumberLiteralExpression"/>.
|
|
/// </summary>
|
|
/// <param name="number">The numeric value.</param>
|
|
public static implicit operator Expression(decimal number) => new NumberLiteralExpression(number);
|
|
|
|
/// <summary>
|
|
/// Implicitly converts a string to a <see cref="StringLiteralExpression"/>.
|
|
/// </summary>
|
|
/// <param name="value">The string value.</param>
|
|
public static implicit operator Expression(string value) => new StringLiteralExpression(value);
|
|
|
|
/// <summary>
|
|
/// Implicitly converts a DateTime to a <see cref="DateTimeLiteralExpression"/>.
|
|
/// </summary>
|
|
/// <param name="dateTime">The DateTime value.</param>
|
|
public static implicit operator Expression(DateTime dateTime) => new DateTimeLiteralExpression(dateTime);
|
|
|
|
/// <summary>
|
|
/// Implicitly converts a DateOnly to a <see cref="DateTimeLiteralExpression"/>.
|
|
/// </summary>
|
|
/// <param name="date">The DateOnly value.</param>
|
|
public static implicit operator Expression(DateOnly date) => new DateTimeLiteralExpression(date.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc));
|
|
#endregion
|
|
|
|
#region Comparison Operators
|
|
/// <summary>
|
|
/// Creates an equality comparison expression (=).
|
|
/// </summary>
|
|
/// <param name="a">The left expression.</param>
|
|
/// <param name="b">The right expression.</param>
|
|
/// <returns>An <see cref="EqualToExpression"/>.</returns>
|
|
public static ComparisonOperatorExpression operator ==(Expression a, Expression b) => new EqualToExpression(a, b);
|
|
|
|
/// <summary>
|
|
/// Creates an inequality comparison expression (!=).
|
|
/// </summary>
|
|
/// <param name="a">The left expression.</param>
|
|
/// <param name="b">The right expression.</param>
|
|
/// <returns>A <see cref="NotEqualToExpression"/>.</returns>
|
|
public static ComparisonOperatorExpression operator !=(Expression a, Expression b) => new NotEqualToExpression(a, b);
|
|
|
|
/// <summary>
|
|
/// Creates a greater-than comparison expression (>).
|
|
/// </summary>
|
|
/// <param name="a">The left expression.</param>
|
|
/// <param name="b">The right expression.</param>
|
|
/// <returns>A <see cref="GreaterThanExpression"/>.</returns>
|
|
public static ComparisonOperatorExpression operator >(Expression a, Expression b) => new GreaterThanExpression(a, b);
|
|
|
|
/// <summary>
|
|
/// Creates a less-than comparison expression (<).
|
|
/// </summary>
|
|
/// <param name="a">The left expression.</param>
|
|
/// <param name="b">The right expression.</param>
|
|
/// <returns>A <see cref="LessThanExpression"/>.</returns>
|
|
public static ComparisonOperatorExpression operator <(Expression a, Expression b) => new LessThanExpression(a, b);
|
|
|
|
/// <summary>
|
|
/// Creates a greater-than-or-equal comparison expression (>=).
|
|
/// </summary>
|
|
/// <param name="a">The left expression.</param>
|
|
/// <param name="b">The right expression.</param>
|
|
/// <returns>A <see cref="GreaterThanOrEqualToExpression"/>.</returns>
|
|
public static ComparisonOperatorExpression operator >=(Expression a, Expression b) => new GreaterThanOrEqualToExpression(a, b);
|
|
|
|
/// <summary>
|
|
/// Creates a less-than-or-equal comparison expression (<=).
|
|
/// </summary>
|
|
/// <param name="a">The left expression.</param>
|
|
/// <param name="b">The right expression.</param>
|
|
/// <returns>A <see cref="LessThanOrEqualToExpression"/>.</returns>
|
|
public static ComparisonOperatorExpression operator <=(Expression a, Expression b) => new LessThanOrEqualToExpression(a, b);
|
|
#endregion
|
|
|
|
#region Arithmetic Operators
|
|
/// <summary>
|
|
/// Creates an addition expression (+).
|
|
/// </summary>
|
|
/// <param name="a">The left expression.</param>
|
|
/// <param name="b">The right expression.</param>
|
|
/// <returns>An <see cref="AdditionExpression"/>.</returns>
|
|
public static ArithmeticExpression operator +(Expression a, Expression b) => new AdditionExpression(a, b);
|
|
|
|
/// <summary>
|
|
/// Creates a subtraction expression (-).
|
|
/// </summary>
|
|
/// <param name="a">The left expression.</param>
|
|
/// <param name="b">The right expression.</param>
|
|
/// <returns>A <see cref="SubtractionExpression"/>.</returns>
|
|
public static ArithmeticExpression operator -(Expression a, Expression b) => new SubtractionExpression(a, b);
|
|
|
|
/// <summary>
|
|
/// Creates a multiplication expression (*).
|
|
/// </summary>
|
|
/// <param name="a">The left expression.</param>
|
|
/// <param name="b">The right expression.</param>
|
|
/// <returns>A <see cref="MultiplicationExpression"/>.</returns>
|
|
public static ArithmeticExpression operator *(Expression a, Expression b) => new MultiplicationExpression(a, b);
|
|
|
|
/// <summary>
|
|
/// Creates a division expression (/).
|
|
/// </summary>
|
|
/// <param name="a">The left expression.</param>
|
|
/// <param name="b">The right expression.</param>
|
|
/// <returns>A <see cref="DivisionExpression"/>.</returns>
|
|
public static ArithmeticExpression operator /(Expression a, Expression b) => new DivisionExpression(a, b);
|
|
#endregion
|
|
}
|
|
|
|
|