using Strata.SqlTools.SqlBreakdown.Expressions; using Strata.SqlTools.SqlBreakdown.Expressions.Literals; namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests; [TestFixture] public class GenericColumnExpressionTests : ExpressionTestsBase { private static IEnumerable GenericColumnExpressionTestCases() { var testCases = new[] { new ExpressionTestCase { Name = "WithArithmeticOperatorsAndLiterals_{m}", Arrange = new Dictionary { ["price"] = new GenericColumnExpression("Price", "Products"), ["quantity"] = new GenericColumnExpression("Quantity", "Products") }, Act = (columns, visitor) => { var price = columns["price"]; var quantity = columns["quantity"]; var priceWithTax = price * new NumberLiteralExpression(1.1m); var priceWithFee = price + new NumberLiteralExpression(10); var revenue = quantity * price; return new Dictionary { ["priceWithTax"] = priceWithTax.Accept(visitor), ["priceWithFee"] = priceWithFee.Accept(visitor), ["revenue"] = revenue.Accept(visitor) }; }, Assertions = result => { var results = (Dictionary)result; Assert.That(results["priceWithTax"], Does.Contain("Price")); Assert.Multiple(() => { Assert.That(results["priceWithTax"], Does.Contain("1.1")); Assert.That(results["priceWithFee"], Does.Contain("Price")); }); Assert.Multiple(() => { Assert.That(results["priceWithFee"], Does.Contain("10")); Assert.That(results["revenue"], Does.Contain("Quantity")); }); Assert.That(results["revenue"], Does.Contain("Price")); return true; } }, new ExpressionTestCase { Name = "WithComparisonOperators_{m}", Arrange = new Dictionary { ["price"] = new GenericColumnExpression("Price", "Products"), ["category"] = new GenericColumnExpression("Category", "Products") }, Act = (columns, visitor) => { var price = columns["price"]; var category = columns["category"]; var priceCondition = price > 100; var categoryCondition = category == "Electronics"; return new Dictionary { ["priceCondition"] = priceCondition.Accept(visitor), ["categoryCondition"] = categoryCondition.Accept(visitor) }; }, Assertions = result => { var results = (Dictionary)result; Assert.That(results["priceCondition"], Does.Contain("Price")); Assert.That(results["priceCondition"], Does.Contain("100")); Assert.That(results["categoryCondition"], Does.Contain("Category")); Assert.That(results["categoryCondition"], Does.Contain("Electronics")); return true; } }, new ExpressionTestCase { Name = "InQueryBreakdown_{m}", Arrange = new Dictionary { ["productId"] = new GenericColumnExpression("ProductID", "Products"), ["price"] = new GenericColumnExpression("Price", "Products"), ["category"] = new GenericColumnExpression("Category", "Products") }, Act = (columns, visitor) => { var query = new Breakdowns.SqlServer.QueryBreakdown(); query.FromClause.Clause = "Products"; var productId = columns["productId"]; var price = columns["price"]; var category = columns["category"]; query.AddSelectExpression(productId, "ID"); query.AddSelectExpression(price * new NumberLiteralExpression(1.1m), "PriceWithTax"); query.AddSelectExpression(price + new NumberLiteralExpression(10), "PriceWithFee"); query.AddWhereExpression(price > 100); query.AddWhereExpression(category == "Electronics", null, "AND"); return query.GetSql(); }, Assertions = result => { var sql = (string)result; Assert.That(sql, Does.Contain("ProductID")); Assert.That(sql, Does.Contain("Price")); Assert.That(sql, Does.Contain("Category")); Assert.That(sql, Does.Contain("Products")); return true; } }, new ExpressionTestCase { Name = "ComplexArithmetic_{m}", Arrange = new Dictionary { ["quantity"] = new GenericColumnExpression("Quantity", "OrderDetails"), ["unitPrice"] = new GenericColumnExpression("UnitPrice", "OrderDetails"), ["discount"] = new GenericColumnExpression("Discount", "OrderDetails") }, Act = (columns, visitor) => { var quantity = columns["quantity"]; var unitPrice = columns["unitPrice"]; var discount = columns["discount"]; var totalRevenue = (quantity * unitPrice) * (new NumberLiteralExpression(1) - discount); return totalRevenue.Accept(visitor); }, Assertions = result => { var sql = (string)result; Assert.That(sql, Does.Contain("Quantity")); Assert.That(sql, Does.Contain("UnitPrice")); Assert.That(sql, Does.Contain("Discount")); return true; } }, new ExpressionTestCase { Name = "WithSchema_{m}", Arrange = new Dictionary { ["customerId"] = new GenericColumnExpression("CustomerID", "dbo", "Customers"), ["orderDate"] = new GenericColumnExpression("OrderDate", "dbo", "Orders") }, Act = (columns, visitor) => { return new Dictionary { ["customerResult"] = columns["customerId"].Accept(visitor), ["orderResult"] = columns["orderDate"].Accept(visitor) }; }, Assertions = result => { var results = (Dictionary)result; Assert.Multiple(() => { Assert.That(results["customerResult"], Does.Contain("CustomerID")); Assert.That(results["orderResult"], Does.Contain("OrderDate")); }); return true; } }, new ExpressionTestCase { Name = "MultipleComparisonOperators_{m}", Arrange = new Dictionary { ["unitPrice"] = new GenericColumnExpression("UnitPrice", "Products"), ["minPrice"] = new GenericColumnExpression("MinPrice", "PriceRanges"), ["maxPrice"] = new GenericColumnExpression("MaxPrice", "PriceRanges") }, Act = (columns, visitor) => { var unitPrice = columns["unitPrice"]; var minPrice = columns["minPrice"]; var maxPrice = columns["maxPrice"]; var lowerBound = unitPrice >= minPrice; var upperBound = unitPrice <= maxPrice; return new Dictionary { ["lowerBound"] = lowerBound.Accept(visitor), ["upperBound"] = upperBound.Accept(visitor) }; }, Assertions = result => { var results = (Dictionary)result; Assert.That(results["lowerBound"], Does.Contain("UnitPrice")); Assert.Multiple(() => { Assert.That(results["lowerBound"], Does.Contain("MinPrice")); Assert.That(results["upperBound"], Does.Contain("UnitPrice")); }); Assert.That(results["upperBound"], Does.Contain("MaxPrice")); return true; } } }; foreach (var testCase in testCases) { yield return new TestCaseData(testCase).SetName(testCase.Name); } } [TestCaseSource(nameof(GenericColumnExpressionTestCases))] public void GenericColumnExpression_GeneratesCorrectSql(ExpressionTestCase testCase) => ExecuteExpressionTest(testCase); }