Files
sql-utilities/tests/Strata.SqlTools.LinqToSql.Tests/LinqQueryBreakdownWithClauseTests.cs
T

290 lines
9.6 KiB
C#

using Strata.SqlTools.Breakdowns.LinqToSql;
using Strata.SqlTools.Builders.LinqToSql;
using Strata.SqlTools.SqlBreakdown.Classes;
namespace Strata.SqlTools.SqlBreakdown.Tests.LinqToSql;
[TestFixture]
public class LinqQueryBreakdownWithClauseTests
{
#region Basic WITH Clause Tests
[Test]
public void LinqQueryBreakdown_SupportsWithClause_ViaInheritance()
{
// Arrange
var cte = new LinqQueryBreakdown("id, name", "users", "status = 'active'");
var mainQuery = new LinqQueryBreakdown("*", "active_users_cte");
// Act
mainQuery.AddWithClause("active_users", cte);
// Assert
Assert.That(mainQuery.WithClauses, Has.Count.EqualTo(1));
Assert.That(mainQuery.WithClauses[0].TableName, Is.EqualTo("active_users"));
Assert.That(mainQuery.WithClauses[0].Query, Is.EqualTo(cte));
}
[Test]
public void LinqQueryBreakdown_GeneratesSql_WithSimpleCTE()
{
// Arrange
var cte = new LinqQueryBreakdown("id, name", "users");
var mainQuery = new LinqQueryBreakdown("*", "active_users_cte");
mainQuery.AddWithClause("active_users", cte);
// Act
var sql = mainQuery.GetSql();
// Assert
Assert.That(sql, Contains.Substring("WITH"));
Assert.That(sql, Contains.Substring("active_users AS"));
}
[Test]
public void LinqQueryBreakdown_WithMultipleCTEs_GeneratesAllClauses()
{
// Arrange
var cte1 = new LinqQueryBreakdown("id, status", "users", "status = 'active'");
var cte2 = new LinqQueryBreakdown("user_id, created", "orders", "created >= CURRENT_DATE");
var mainQuery = new LinqQueryBreakdown("*", "results");
mainQuery.AddWithClause("active_users", cte1);
mainQuery.AddWithClause("recent_orders", cte2);
// Act
var sql = mainQuery.GetSql();
// Assert
Assert.That(sql, Contains.Substring("WITH"));
Assert.That(sql, Contains.Substring("active_users AS"));
Assert.That(sql, Contains.Substring("recent_orders AS"));
}
#endregion
#region CTE Parameter Inheritance Tests
[Test]
public void LinqQueryBreakdown_CollectsCTEParameters()
{
// Arrange
var cte = new LinqQueryBreakdown("id, name", "users");
cte.AddParameter("Status", "active");
var mainQuery = new LinqQueryBreakdown("*", "results");
mainQuery.AddParameter("Limit", 100);
mainQuery.AddWithClause("active_users", cte);
// Act
var merged = mainQuery.GetMergedParameters();
// Assert
var keys = merged.Keys.ToList();
Assert.That(keys.Any(k => k.Contains("Status")), "Should include CTE parameters");
Assert.That(keys.Any(k => k.Contains("Limit")), "Should include main query parameters");
}
[Test]
public void LinqQueryBreakdown_MainQueryParamsPrecedence()
{
// Arrange
var cte = new LinqQueryBreakdown("id", "data");
cte.AddParameter("Value", "cte_value");
var mainQuery = new LinqQueryBreakdown("*", "results");
mainQuery.AddParameter("Value", "main_value");
mainQuery.AddWithClause("data_cte", cte);
// Act
var merged = mainQuery.GetMergedParameters();
// Assert
var valueKey = merged.Keys.FirstOrDefault(k => k.Contains("Value"));
Assert.That(valueKey, Is.Not.Null, "Should have a Value parameter");
Assert.That(merged[valueKey], Is.EqualTo("main_value"), "Main query parameter should take precedence");
}
#endregion
#region Builder Integration Tests
[Test]
public void LinqQueryBreakdownBuilder_BuiltQuerySupportsWithClauses()
{
// Arrange
var builder = LinqQueryBreakdownBuilder.CreateForTable("users")
.SelectAll()
.Where("id > 0");
var mainQuery = builder.Build();
var cte = new LinqQueryBreakdown("id, name", "active_users_data");
cte.AddParameter("Status", "active");
// Act
mainQuery.AddWithClause("active_users", cte);
var sql = mainQuery.GetSql();
// Assert
Assert.That(sql, Contains.Substring("WITH"));
Assert.That(sql, Contains.Substring("active_users AS"));
}
[Test]
public void LinqQueryBreakdownBuilder_CanAddCTEToBuiltQuery()
{
// Arrange
var builder = LinqQueryBreakdownBuilder.CreateForTable("orders");
builder.SelectAll().Where("status != 'cancelled'");
var query = builder.Build();
var cte1 = new LinqQueryBreakdown("id, order_id", "recent_orders", "created >= CURRENT_DATE");
cte1.AddParameter("MinDate", DateTime.Today.AddDays(-30));
var cte2 = new LinqQueryBreakdown("id, name", "users", "active = 1");
cte2.AddParameter("Status", "active");
// Act
query.AddWithClause("recent_orders", cte1);
query.AddWithClause("active_users", cte2);
var merged = query.GetMergedParameters();
// Assert
Assert.That(query.WithClauses, Has.Count.EqualTo(2));
var keys = merged.Keys.ToList();
Assert.That(keys.Any(k => k.Contains("MinDate")));
Assert.That(keys.Any(k => k.Contains("Status")));
}
#endregion
#region Recursive CTE Tests
[Test]
public void LinqQueryBreakdown_SupportsRecursiveCTE_ViaInheritance()
{
// Arrange
var anchorQuery = new LinqQueryBreakdown("id, manager_id, name, 1 as level", "employees", "manager_id IS NULL");
var recursiveQuery = new LinqQueryBreakdown(
"e.id, e.manager_id, e.name, h.level + 1",
"employees e INNER JOIN hierarchy h ON e.manager_id = h.id"
);
var mainQuery = new LinqQueryBreakdown("*", "hierarchy");
var withClause = new WithClause("hierarchy", anchorQuery)
{
IsRecursive = true,
RecursiveQuery = recursiveQuery
};
mainQuery.AddWithClause(withClause);
// Act
var sql = mainQuery.GetSql();
// Assert
Assert.That(sql, Contains.Substring("WITH RECURSIVE"));
Assert.That(sql, Contains.Substring("hierarchy AS"));
Assert.That(sql, Contains.Substring("UNION ALL"));
}
[Test]
public void LinqQueryBreakdown_RecursiveCTE_CollectsAllParameters()
{
// Arrange
var anchorQuery = new LinqQueryBreakdown("id, manager_id", "employees");
anchorQuery.AddParameter("AnchorLevel", 1);
var recursiveQuery = new LinqQueryBreakdown("e.id, e.manager_id", "employees e INNER JOIN org_hier h ON e.manager_id = h.id");
recursiveQuery.AddParameter("MaxLevel", 10);
var mainQuery = new LinqQueryBreakdown("*", "org_hierarchy");
mainQuery.AddParameter("QueryLimit", 100);
var withClause = new WithClause("org_hierarchy", anchorQuery)
{
IsRecursive = true,
RecursiveQuery = recursiveQuery
};
mainQuery.AddWithClause(withClause);
// Act
var merged = mainQuery.GetMergedParameters();
// Assert
var keys = merged.Keys.ToList();
Assert.That(keys.Any(k => k.Contains("AnchorLevel")), "Should include anchor parameters");
Assert.That(keys.Any(k => k.Contains("MaxLevel")), "Should include recursive parameters");
Assert.That(keys.Any(k => k.Contains("QueryLimit")), "Should include main query parameters");
}
#endregion
#region SQL Generation Tests
[Test]
public void LinqQueryBreakdown_GeneratesProperSqlWithParameters()
{
// Arrange
var cte = new LinqQueryBreakdown("id, name, salary", "employees", "salary > @MinSalary");
cte.AddParameter("MinSalary", 50000);
var mainQuery = new LinqQueryBreakdown("user_id, user_name, compensation", "employee_summary");
mainQuery.AddParameter("DepartmentId", 1);
mainQuery.AddWithClause("high_earners", cte);
// Act
var sql = mainQuery.GetSql();
// Assert
Assert.That(sql, Contains.Substring("WITH"));
Assert.That(sql, Contains.Substring("high_earners AS"));
}
[Test]
public void LinqQueryBreakdown_ToSqlServerSql_WithCTE()
{
// Arrange
var cte = new LinqQueryBreakdown("id, name", "base_data");
var mainQuery = new LinqQueryBreakdown("*", "cte_data");
mainQuery.AddWithClause("base", cte);
// Act
var sql = mainQuery.GetSql();
// Assert
Assert.That(sql, Is.Not.Null);
// GetSql() should include WITH clause (inherited from QueryBreakdown)
Assert.That(sql, Contains.Substring("WITH"), "GetSql() should generate WITH clause");
}
[Test]
public void LinqQueryBreakdown_ComplexQuery_WithNestdCTEsAndParameters()
{
// Arrange
var innerCte = new LinqQueryBreakdown("id, dept_id", "employees");
innerCte.AddParameter("InnerParam", "inner_value");
var outerCte = new LinqQueryBreakdown("*", "filtered_employees");
outerCte.AddParameter("OuterParam", "outer_value");
outerCte.AddWithClause("emp_summary", innerCte);
var mainQuery = new LinqQueryBreakdown("*", "final_results");
mainQuery.AddParameter("MainParam", "main_value");
mainQuery.AddWithClause("emp_data", outerCte);
// Act
var merged = mainQuery.GetMergedParameters();
var sql = mainQuery.GetSql();
// Assert
var keys = merged.Keys.ToList();
Assert.That(keys.Any(k => k.Contains("InnerParam")));
Assert.That(keys.Any(k => k.Contains("OuterParam")));
Assert.That(keys.Any(k => k.Contains("MainParam")));
Assert.That(sql, Contains.Substring("WITH"));
}
#endregion
}