chore: initial git load of code space
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Classes;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Functions.Aggregate;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Literals;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
|
||||
|
||||
[TestFixture]
|
||||
public class ArithmeticExpressionTests : ExpressionTestsBase
|
||||
{
|
||||
private static IEnumerable<TestCaseData> ArithmeticExpressionTestCases()
|
||||
{
|
||||
var testCases = new[]
|
||||
{
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "WithSum_{m}",
|
||||
Arrange = new Dictionary<string, Expression>
|
||||
{
|
||||
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES")),
|
||||
["cost"] = new RegisteredTableColumnExpression(3, "COST", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
|
||||
},
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var revenue = columns["revenue"];
|
||||
var cost = columns["cost"];
|
||||
var addExp = new SumFunction(revenue - cost - 1001);
|
||||
return addExp.Accept(visitor);
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var sql = (string)result;
|
||||
Assert.That(sql, Does.Contain("SUM"));
|
||||
Assert.That(sql, Does.Contain("-"));
|
||||
Assert.That(sql, Does.Contain("1001"));
|
||||
Assert.That(sql, Is.EqualTo("SUM(PES.NET_REVENUE - PES.COST - 1001)"));
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "Addition_{m}",
|
||||
Arrange = new Dictionary<string, Expression>
|
||||
{
|
||||
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
|
||||
},
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var revenue = columns["revenue"];
|
||||
var result = revenue + new NumberLiteralExpression(1000);
|
||||
return result.Accept(visitor);
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var sql = (string)result;
|
||||
Assert.That(sql, Does.Contain("NET_REVENUE"));
|
||||
Assert.That(sql, Does.Contain("+"));
|
||||
Assert.That(sql, Does.Contain("1000"));
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "Multiplication_{m}",
|
||||
Arrange = new Dictionary<string, Expression>
|
||||
{
|
||||
["cost"] = new RegisteredTableColumnExpression(3, "COST", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
|
||||
},
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var cost = columns["cost"];
|
||||
var result = cost * new NumberLiteralExpression(1.5m);
|
||||
return result.Accept(visitor);
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var sql = (string)result;
|
||||
Assert.That(sql, Does.Contain("COST"));
|
||||
Assert.That(sql, Does.Contain("*"));
|
||||
Assert.That(sql, Does.Contain("1.5"));
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "Division_{m}",
|
||||
Arrange = new Dictionary<string, Expression>
|
||||
{
|
||||
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
|
||||
},
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var revenue = columns["revenue"];
|
||||
var result = revenue / new NumberLiteralExpression(2);
|
||||
return result.Accept(visitor);
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var sql = (string)result;
|
||||
Assert.That(sql, Does.Contain("NET_REVENUE"));
|
||||
Assert.That(sql, Does.Contain("/"));
|
||||
Assert.That(sql, Does.Contain("2"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var testCase in testCases)
|
||||
{
|
||||
yield return new TestCaseData(testCase).SetName(testCase.Name);
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(ArithmeticExpressionTestCases))]
|
||||
public void ArithmeticExpression_GeneratesCorrectSql(ExpressionTestCase testCase)
|
||||
=> ExecuteExpressionTest(testCase);
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Classes;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional.Comparisons;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional.Logical;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
|
||||
|
||||
[TestFixture]
|
||||
public class BooleanExpressionTests : ExpressionTestsBase
|
||||
{
|
||||
[Test]
|
||||
public void BooleanExpression_AndOperator_ChainsCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var greaterThan250Exp = new GreaterThanExpression(_costColumnExp, 250);
|
||||
BooleanExpression original = BooleanExpression.False;
|
||||
|
||||
// Act
|
||||
original &= greaterThan250Exp;
|
||||
var firstResult = original;
|
||||
original &= greaterThan250Exp;
|
||||
var secondResult = original;
|
||||
|
||||
// Assert
|
||||
Assert.That(firstResult, Is.Not.SameAs(BooleanExpression.False));
|
||||
Assert.That(firstResult, Is.AssignableTo<BooleanExpression>());
|
||||
Assert.That(secondResult, Is.Not.SameAs(BooleanExpression.False));
|
||||
Assert.That(secondResult, Is.TypeOf<AndExpression>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BooleanExpression_ComplexWithOperators_CreatesExpression()
|
||||
{
|
||||
// Arrange
|
||||
var paramFoobar = new ParameterExpression("FOOBAR");
|
||||
|
||||
// Act
|
||||
#pragma warning disable S2178 // Short-circuit logic should be used in boolean contexts
|
||||
var andComp = _revenueColumnExp > 100 & _costColumnExp >= 250 | _nameColumnExp == paramFoobar;
|
||||
#pragma warning restore S2178
|
||||
|
||||
// Assert
|
||||
Assert.That(andComp, Is.Not.Null);
|
||||
Assert.That(andComp, Is.AssignableTo<BooleanExpression>());
|
||||
}
|
||||
|
||||
private static IEnumerable<TestCaseData> BooleanExpressionTestCases()
|
||||
{
|
||||
var testCases = new[]
|
||||
{
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "GreaterThan_{m}",
|
||||
Arrange = new Dictionary<string, Expression>
|
||||
{
|
||||
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
|
||||
},
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var revenue = columns["revenue"];
|
||||
var greaterThan100Exp = new GreaterThanExpression(revenue, 100);
|
||||
return greaterThan100Exp;
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var expression = (BooleanExpression)result;
|
||||
Assert.That(expression, Is.Not.Null);
|
||||
Assert.That(expression, Is.TypeOf<GreaterThanExpression>());
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "And_{m}",
|
||||
Arrange = new Dictionary<string, Expression>
|
||||
{
|
||||
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES")),
|
||||
["cost"] = new RegisteredTableColumnExpression(3, "COST", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
|
||||
},
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var revenue = columns["revenue"];
|
||||
var cost = columns["cost"];
|
||||
var greaterThan100Exp = new GreaterThanExpression(revenue, 100);
|
||||
var greaterThan250Exp = new GreaterThanExpression(cost, 250);
|
||||
var andExp1 = new AndExpression(greaterThan100Exp, greaterThan250Exp);
|
||||
return andExp1;
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var expression = (BooleanExpression)result;
|
||||
Assert.That(expression, Is.Not.Null);
|
||||
Assert.That(expression, Is.TypeOf<AndExpression>());
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "Or_{m}",
|
||||
Arrange = new Dictionary<string, Expression>
|
||||
{
|
||||
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES")),
|
||||
["cost"] = new RegisteredTableColumnExpression(3, "COST", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
|
||||
},
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var revenue = columns["revenue"];
|
||||
var cost = columns["cost"];
|
||||
#pragma warning disable S2178 // Short-circuit logic should be used in boolean contexts
|
||||
var orComp = revenue > 100 | cost >= 250;
|
||||
#pragma warning restore S2178
|
||||
return orComp;
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var expression = (BooleanExpression)result;
|
||||
Assert.That(expression, Is.Not.Null);
|
||||
Assert.That(expression, Is.AssignableTo<BooleanExpression>());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var testCase in testCases)
|
||||
{
|
||||
yield return new TestCaseData(testCase).SetName(testCase.Name);
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(BooleanExpressionTestCases))]
|
||||
public void BooleanExpression_GeneratesCorrectExpression(ExpressionTestCase testCase)
|
||||
=> ExecuteExpressionTest(testCase);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Classes;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Functions.Aggregate;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Functions.Conditional;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
|
||||
|
||||
[TestFixture]
|
||||
public class ConditionalExpressionTests : ExpressionTestsBase
|
||||
{
|
||||
private static IEnumerable<TestCaseData> ConditionalExpressionTestCases()
|
||||
{
|
||||
var testCases = new[]
|
||||
{
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "CaseExpression_{m}",
|
||||
Arrange = new Dictionary<string, Expression>(),
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var table = new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES");
|
||||
var nameCol = new RegisteredTableColumnExpression(1, "DEPARTMENT_NAME", table);
|
||||
var revenueCol = new RegisteredTableColumnExpression(2, "NET_REVENUE", table);
|
||||
var caseExp = new CaseExpression(nameCol == "department 1", revenueCol, 0);
|
||||
return caseExp.Accept(visitor);
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var sql = (string)result;
|
||||
Assert.That(sql, Does.Contain("CASE"));
|
||||
Assert.That(sql, Does.Contain("WHEN"));
|
||||
Assert.That(sql, Does.Contain("THEN"));
|
||||
Assert.That(sql, Does.Contain("ELSE"));
|
||||
Assert.That(sql, Does.Contain("END"));
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "CaseExpressionWithSum_{m}",
|
||||
Arrange = new Dictionary<string, Expression>(),
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var table = new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES");
|
||||
var nameCol = new RegisteredTableColumnExpression(1, "DEPARTMENT_NAME", table);
|
||||
var revenueCol = new RegisteredTableColumnExpression(2, "NET_REVENUE", table);
|
||||
var caseExp = new CaseExpression(nameCol == "department 1", revenueCol, 0);
|
||||
var sumCaseExp = new SumFunction(caseExp);
|
||||
return sumCaseExp.Accept(visitor);
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var sql = (string)result;
|
||||
Assert.That(sql, Does.Contain("SUM"));
|
||||
Assert.That(sql, Does.Contain("CASE"));
|
||||
Assert.That(sql, Does.Contain("WHEN"));
|
||||
Assert.That(sql, Is.EqualTo("SUM(CASE\n WHEN PES.DEPARTMENT_NAME = 'department 1' THEN PES.NET_REVENUE\n ELSE 0\nEND)"));
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "CaseExpressionWithSumInSelectColumn_{m}",
|
||||
Arrange = new Dictionary<string, Expression>(),
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var table = new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES");
|
||||
var nameCol = new RegisteredTableColumnExpression(1, "DEPARTMENT_NAME", table);
|
||||
var revenueCol = new RegisteredTableColumnExpression(2, "NET_REVENUE", table);
|
||||
var caseExp = new CaseExpression(nameCol == "department 1", revenueCol, 0);
|
||||
var sumCaseExp = new SumFunction(caseExp);
|
||||
var column = new SelectClauseColumn(sumCaseExp, "mySumCaseCol");
|
||||
return column.Accept(visitor);
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var sql = (string)result;
|
||||
Assert.That(sql, Does.Contain("SUM"));
|
||||
Assert.That(sql, Does.Contain("CASE"));
|
||||
Assert.That(sql, Does.Contain("mySumCaseCol"));
|
||||
Assert.That(sql, Is.EqualTo("SUM(CASE\n WHEN PES.DEPARTMENT_NAME = 'department 1' THEN PES.NET_REVENUE\n ELSE 0\nEND) AS mySumCaseCol"));
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "IfThenElseExpression_{m}",
|
||||
Arrange = new Dictionary<string, Expression>(),
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var table = new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES");
|
||||
var nameCol = new RegisteredTableColumnExpression(1, "DEPARTMENT_NAME", table);
|
||||
var revenueCol = new RegisteredTableColumnExpression(2, "NET_REVENUE", table);
|
||||
var costCol = new RegisteredTableColumnExpression(3, "COST", table);
|
||||
var ifElseExp = new IfThenElseExpression(nameCol == "myDeptName", revenueCol, costCol);
|
||||
return ifElseExp.Accept(visitor);
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var sql = (string)result;
|
||||
Assert.That(sql, Does.Contain("IFF"));
|
||||
Assert.That(sql, Is.EqualTo("IFF(PES.DEPARTMENT_NAME = 'myDeptName', PES.NET_REVENUE, PES.COST)"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var testCase in testCases)
|
||||
{
|
||||
yield return new TestCaseData(testCase).SetName(testCase.Name);
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(ConditionalExpressionTestCases))]
|
||||
public void ConditionalExpression_GeneratesCorrectSql(ExpressionTestCase testCase)
|
||||
=> ExecuteExpressionTest(testCase);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Classes;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
|
||||
|
||||
[TestFixture]
|
||||
public class DateFunctionTests : ExpressionTestsBase
|
||||
{
|
||||
private static IEnumerable<TestCaseData> DateFunctionTestCases()
|
||||
{
|
||||
var testCases = new[]
|
||||
{
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "GetFiscalYearMonthExpression_{m}",
|
||||
Arrange = new Dictionary<string, Expression>
|
||||
{
|
||||
["dischargeDate"] = new RegisteredTableColumnExpression(4, "DISCHARGE_DATE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
|
||||
},
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
var dischargeDate = columns["dischargeDate"];
|
||||
var fiscal = TestExpressionFactory.GetFiscalYearMonthExpression(dischargeDate, 7, 1);
|
||||
return fiscal.Accept(visitor);
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var sql = (string)result;
|
||||
Assert.That(sql, Is.Not.Null);
|
||||
Assert.That(sql.Length, Is.GreaterThan(0));
|
||||
Assert.That(sql, Is.EqualTo("DATE_TRUNC('month', DATEADD('month', 6, PES.DISCHARGE_DATE))"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var testCase in testCases)
|
||||
{
|
||||
yield return new TestCaseData(testCase).SetName(testCase.Name);
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(DateFunctionTestCases))]
|
||||
public void DateFunction_GeneratesCorrectSql(ExpressionTestCase testCase)
|
||||
=> ExecuteExpressionTest(testCase);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using Strata.SqlTools.SqlServer.ExpressionFactory.Query;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
|
||||
|
||||
[TestFixture]
|
||||
public class ExpressionFactoryFilterTests : ExpressionTestsBase
|
||||
{
|
||||
private static IEnumerable<TestCaseData> FilterTestCases()
|
||||
{
|
||||
yield return new TestCaseData(
|
||||
new Filter(2, FilterType.List, new object[] { "foo", "bar", "baz", 1234 }, Array.Empty<FilterCondition>(), DatePart.Continuous, false, 0, 0),
|
||||
"DEPT.NAME IN ('foo', 'bar', 'baz', 1234)"
|
||||
).SetName("ListFilterContinuous_{m}");
|
||||
|
||||
yield return new TestCaseData(
|
||||
new Filter(4, FilterType.List, new[] { "FY2019", "FY2020", "FY2021", "FY2022" }, Array.Empty<FilterCondition>(), DatePart.FiscalYear, false, 0, 0),
|
||||
"(DEPT.DISCHARGE_DATE >= '2018-07-01' AND DEPT.DISCHARGE_DATE < '2019-07-01') OR \n(DEPT.DISCHARGE_DATE >= '2019-07-01' AND DEPT.DISCHARGE_DATE < '2020-07-01') OR \n(DEPT.DISCHARGE_DATE >= '2020-07-01' AND DEPT.DISCHARGE_DATE < '2021-07-01') OR \n(DEPT.DISCHARGE_DATE >= '2021-07-01' AND DEPT.DISCHARGE_DATE < '2022-07-01')"
|
||||
).SetName("DateListFilterFiscalYear_{m}");
|
||||
|
||||
yield return new TestCaseData(
|
||||
new Filter(4, FilterType.List, new[] { "01-2020" }, Array.Empty<FilterCondition>(), DatePart.Month, false, 0, 0),
|
||||
"DEPT.DISCHARGE_DATE >= '2020-01-01' AND DEPT.DISCHARGE_DATE < '2020-02-01'"
|
||||
).SetName("MonthListFilter_{m}");
|
||||
|
||||
yield return new TestCaseData(
|
||||
new Filter(4, FilterType.Calendar, new[] { "01/01/2019", "01/01/2023" }, Array.Empty<FilterCondition>(), DatePart.Month, false, 0, 0),
|
||||
"DEPT.DISCHARGE_DATE >= '2019-01-01' AND DEPT.DISCHARGE_DATE < '2023-01-01'"
|
||||
).SetName("CalendarFilter_{m}");
|
||||
|
||||
yield return new TestCaseData(
|
||||
new Filter(4, FilterType.Timeframe, new object[] { }, Array.Empty<FilterCondition>(), DatePart.Month, false, 1, 3),
|
||||
"DEPT.DISCHARGE_DATE >= '2026-03-01' AND DEPT.DISCHARGE_DATE < '2026-06-01'"
|
||||
).SetName("TimeframeFilter_{m}");
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(FilterTestCases))]
|
||||
public void ExpressionFactory_Filter_GeneratesCorrectSql(Filter filter, string expectedSql)
|
||||
{
|
||||
// Arrange
|
||||
var factory = new TestExpressionFactory();
|
||||
|
||||
// Act
|
||||
var condition = factory.CreateBooleanExpression(filter);
|
||||
var result = condition.Accept(_sqlVisitor);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.Length, Is.GreaterThan(0));
|
||||
Assert.That(result, Is.EqualTo(expectedSql));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional.Comparisons;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
|
||||
|
||||
[TestFixture]
|
||||
public class ExpressionObjectTests : ExpressionTestsBase
|
||||
{
|
||||
[Test]
|
||||
public void RegisteredTableColumnExpression_CreatesWithProperties()
|
||||
{
|
||||
// Arrange & Act
|
||||
var columnExp = new RegisteredTableColumnExpression(5, "TEST_COLUMN", _table);
|
||||
|
||||
// Assert
|
||||
Assert.That(columnExp, Is.Not.Null);
|
||||
Assert.That(columnExp.ColumnName, Is.EqualTo("TEST_COLUMN"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParameterExpression_CreatesWithName()
|
||||
{
|
||||
// Arrange & Act
|
||||
var paramExp = new ParameterExpression("MY_PARAM");
|
||||
|
||||
// Assert
|
||||
Assert.That(paramExp, Is.Not.Null);
|
||||
Assert.That(paramExp.ParameterName, Is.EqualTo("MY_PARAM"));
|
||||
}
|
||||
|
||||
private static IEnumerable<TestCaseData> ComparisonExpressionTestCases()
|
||||
{
|
||||
yield return new TestCaseData("GreaterThanOrEqual", 250, typeof(GreaterThanOrEqualToExpression))
|
||||
.SetName("GreaterThanOrEqual_{m}");
|
||||
|
||||
yield return new TestCaseData("LessThan", 1000, typeof(LessThanExpression))
|
||||
.SetName("LessThan_{m}");
|
||||
|
||||
yield return new TestCaseData("Equals", "TestDept", typeof(EqualToExpression))
|
||||
.SetName("Equals_{m}");
|
||||
|
||||
yield return new TestCaseData("NotIn", new[] { "value1", "value2", "value3" }, typeof(NotInExpression))
|
||||
.SetName("NotIn_{m}");
|
||||
|
||||
yield return new TestCaseData("Like", "%pattern%", typeof(LikeExpression))
|
||||
.SetName("Like_{m}");
|
||||
|
||||
yield return new TestCaseData("Between", new object[] { 0, 5000 }, typeof(BetweenExpression))
|
||||
.SetName("Between_{m}");
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(ComparisonExpressionTestCases))]
|
||||
public void ComparisonExpression_CreatesExpression(string expressionType, object testValue, Type expectedType)
|
||||
{
|
||||
// Arrange & Act
|
||||
BooleanExpression expression = expressionType switch
|
||||
{
|
||||
"GreaterThanOrEqual" => new GreaterThanOrEqualToExpression(_costColumnExp, (int)testValue),
|
||||
"LessThan" => new LessThanExpression(_revenueColumnExp, (int)testValue),
|
||||
"Equals" => new EqualToExpression(_nameColumnExp, (string)testValue),
|
||||
"NotIn" => new NotInExpression(_nameColumnExp, ((string[])testValue).Select(v => (Expression)v).ToArray()),
|
||||
"Like" => new LikeExpression(_nameColumnExp, (string)testValue),
|
||||
"Between" => new BetweenExpression(_revenueColumnExp, (Expression)(int)((object[])testValue)[0], (Expression)(int)((object[])testValue)[1]),
|
||||
_ => throw new ArgumentException($"Unknown expression type: {expressionType}")
|
||||
};
|
||||
|
||||
// Assert
|
||||
Assert.That(expression, Is.Not.Null);
|
||||
Assert.That(expression, Is.TypeOf(expectedType));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions;
|
||||
using Strata.SqlTools.Visitors.Snowflake;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a test case for expression tests with arrange, act, and assert phases.
|
||||
/// </summary>
|
||||
public class ExpressionTestCase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or initializes the name of the test case.
|
||||
/// </summary>
|
||||
public string Name { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or initializes the dictionary of expressions to arrange for the test.
|
||||
/// </summary>
|
||||
public Dictionary<string, Expression> Arrange { get; init; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or initializes the action to execute during the act phase of the test.
|
||||
/// </summary>
|
||||
public Func<Dictionary<string, Expression>, CommandVisitor, object> Act { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or initializes the function to execute during the assert phase of the test that returns true if all assertions pass.
|
||||
/// </summary>
|
||||
public Func<object, bool> Assertions { get; init; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Classes;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional;
|
||||
using Strata.SqlTools.SqlServer.ExpressionFactory.Query;
|
||||
using Strata.SqlTools.SqlBreakdown.Tests.RegisteredTables;
|
||||
using Strata.SqlTools.Visitors.Snowflake;
|
||||
using ExpressionFactoryBase = Strata.SqlTools.SqlServer.ExpressionFactory.ExpressionFactory;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
|
||||
|
||||
/// <summary>
|
||||
/// Test implementation of ExpressionFactory for unit testing.
|
||||
/// Uses July 1 as the fiscal year start date.
|
||||
/// </summary>
|
||||
internal class TestExpressionFactory : ExpressionFactoryBase
|
||||
{
|
||||
protected override DateTime GetCurrentFiscalYearStart()
|
||||
{
|
||||
return new DateTime(DateTime.UtcNow.Year, 7, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
protected override RegisteredTableColumnExpression GetColumnExpression(int dataColumnId)
|
||||
{
|
||||
return RegisteredTableColumns.GetColumn(dataColumnId);
|
||||
}
|
||||
|
||||
// Public wrappers for testing protected methods
|
||||
public new BooleanExpression CreateBooleanExpression(Filter filter) => base.CreateBooleanExpression(filter);
|
||||
public static new Expression GetFiscalYearMonthExpression(Expression dateColumnExpr, int fiscalYearStartMonth, int fiscalYearStartDay)
|
||||
=> ExpressionFactoryBase.GetFiscalYearMonthExpression(dateColumnExpr, fiscalYearStartMonth, fiscalYearStartDay);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base class for expression tests with common setup.
|
||||
/// </summary>
|
||||
public abstract class ExpressionTestsBase
|
||||
{
|
||||
protected RegisteredTableSource _table = null!;
|
||||
protected RegisteredTableColumnExpression _nameColumnExp = null!;
|
||||
protected RegisteredTableColumnExpression _revenueColumnExp = null!;
|
||||
protected RegisteredTableColumnExpression _costColumnExp = null!;
|
||||
protected RegisteredTableColumnExpression _dischargeDateColumnExp = null!;
|
||||
protected CommandVisitor _sqlVisitor = null!;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_table = new RegisteredTableSource(101, "CLIENT_DSS", "FACT_PATIENT_ENCOUNTER_SUMMARY", "PES");
|
||||
_nameColumnExp = new RegisteredTableColumnExpression(1, "DEPARTMENT_NAME", _table);
|
||||
_revenueColumnExp = new RegisteredTableColumnExpression(2, "NET_REVENUE", _table);
|
||||
_costColumnExp = new RegisteredTableColumnExpression(3, "COST", _table);
|
||||
_dischargeDateColumnExp = new RegisteredTableColumnExpression(4, "DISCHARGE_DATE", _table);
|
||||
_sqlVisitor = new CommandVisitor();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes an expression test case with arrange, act, and assert phases.
|
||||
/// </summary>
|
||||
/// <param name="testCase">The test case to execute.</param>
|
||||
protected void ExecuteExpressionTest(ExpressionTestCase testCase)
|
||||
{
|
||||
// Arrange
|
||||
var visitor = new CommandVisitor();
|
||||
var arrange = testCase.Arrange;
|
||||
|
||||
// Act
|
||||
var result = testCase.Act(arrange, visitor);
|
||||
|
||||
// Assert
|
||||
Assert.That(testCase.Assertions(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
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<TestCaseData> GenericColumnExpressionTestCases()
|
||||
{
|
||||
var testCases = new[]
|
||||
{
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "WithArithmeticOperatorsAndLiterals_{m}",
|
||||
Arrange = new Dictionary<string, Expression>
|
||||
{
|
||||
["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<string, string>
|
||||
{
|
||||
["priceWithTax"] = priceWithTax.Accept(visitor),
|
||||
["priceWithFee"] = priceWithFee.Accept(visitor),
|
||||
["revenue"] = revenue.Accept(visitor)
|
||||
};
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var results = (Dictionary<string, string>)result;
|
||||
Assert.That(results["priceWithTax"], Does.Contain("Price"));
|
||||
Assert.That(results["priceWithTax"], Does.Contain("1.1"));
|
||||
Assert.That(results["priceWithFee"], Does.Contain("Price"));
|
||||
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<string, Expression>
|
||||
{
|
||||
["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<string, string>
|
||||
{
|
||||
["priceCondition"] = priceCondition.Accept(visitor),
|
||||
["categoryCondition"] = categoryCondition.Accept(visitor)
|
||||
};
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var results = (Dictionary<string, string>)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<string, Expression>
|
||||
{
|
||||
["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<string, Expression>
|
||||
{
|
||||
["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<string, Expression>
|
||||
{
|
||||
["customerId"] = new GenericColumnExpression("CustomerID", "dbo", "Customers"),
|
||||
["orderDate"] = new GenericColumnExpression("OrderDate", "dbo", "Orders")
|
||||
},
|
||||
Act = (columns, visitor) =>
|
||||
{
|
||||
return new Dictionary<string, string>
|
||||
{
|
||||
["customerResult"] = columns["customerId"].Accept(visitor),
|
||||
["orderResult"] = columns["orderDate"].Accept(visitor)
|
||||
};
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var results = (Dictionary<string, string>)result;
|
||||
Assert.That(results["customerResult"], Does.Contain("CustomerID"));
|
||||
Assert.That(results["orderResult"], Does.Contain("OrderDate"));
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new ExpressionTestCase
|
||||
{
|
||||
Name = "MultipleComparisonOperators_{m}",
|
||||
Arrange = new Dictionary<string, Expression>
|
||||
{
|
||||
["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<string, string>
|
||||
{
|
||||
["lowerBound"] = lowerBound.Accept(visitor),
|
||||
["upperBound"] = upperBound.Accept(visitor)
|
||||
};
|
||||
},
|
||||
Assertions = result =>
|
||||
{
|
||||
var results = (Dictionary<string, string>)result;
|
||||
Assert.That(results["lowerBound"], Does.Contain("UnitPrice"));
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Classes;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Functions.Aggregate;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
|
||||
|
||||
[TestFixture]
|
||||
public class SelectClauseColumnTests : ExpressionTestsBase
|
||||
{
|
||||
private static IEnumerable<TestCaseData> SelectClauseColumnTestCases()
|
||||
{
|
||||
yield return new TestCaseData("TableColumn", "foo_dept_name", "PES.DEPARTMENT_NAME AS foo_dept_name")
|
||||
.SetName("TableColumn_{m}");
|
||||
|
||||
yield return new TestCaseData("SumFunction", "sum_net_rev", "SUM(PES.NET_REVENUE) AS sum_net_rev")
|
||||
.SetName("WithSumFunction_{m}");
|
||||
|
||||
yield return new TestCaseData("Parameter", "my_var_col", ":FOOBAR AS my_var_col")
|
||||
.SetName("WithParameter_{m}");
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(SelectClauseColumnTestCases))]
|
||||
public void SelectClauseColumn_GeneratesCorrectSql(string columnType, string alias, string expectedSql)
|
||||
{
|
||||
// Arrange
|
||||
SelectClauseColumn column = columnType switch
|
||||
{
|
||||
"TableColumn" => SelectClauseColumn.TableColumn(_nameColumnExp, alias),
|
||||
"SumFunction" => new SelectClauseColumn(new SumFunction(_revenueColumnExp), alias),
|
||||
"Parameter" => new SelectClauseColumn(new ParameterExpression("FOOBAR"), alias),
|
||||
_ => throw new ArgumentException($"Unknown column type: {columnType}")
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = column.Accept(_sqlVisitor);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(expectedSql));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user