chore: initial git load of code space
This commit is contained in:
@@ -0,0 +1,279 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional.Logical;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Literals;
|
||||
using Strata.SqlTools.Markdown.Expressions;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.Expressions;
|
||||
|
||||
[TestFixture]
|
||||
public class ExpressionGeneratorTests
|
||||
{
|
||||
private ExpressionGenerator _generator = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_generator = new ExpressionGenerator();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMarkdown_WithSimpleExpression_GeneratesMarkdown()
|
||||
{
|
||||
// Arrange
|
||||
var expression = new NumberLiteralExpression(42);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMarkdown(expression);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("## Expression Structure"));
|
||||
Assert.That(result, Does.Contain("## Expression Type"));
|
||||
Assert.That(result, Does.Contain("## Mermaid Diagram"));
|
||||
Assert.That(result, Does.Contain("NumberLiteralExpression"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMarkdown_WithComparisonExpression_IncludesComparison()
|
||||
{
|
||||
// Arrange
|
||||
Expression left = new NumberLiteralExpression(100);
|
||||
Expression right = new NumberLiteralExpression(50);
|
||||
var expression = left > right;
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMarkdown(expression, "Price Comparison");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("# Price Comparison"));
|
||||
Assert.That(result, Does.Contain("Comparison"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMarkdown_WithArithmeticExpression_IncludesArithmetic()
|
||||
{
|
||||
// Arrange
|
||||
Expression price = new NumberLiteralExpression(100);
|
||||
Expression discount = new NumberLiteralExpression(0.1m);
|
||||
var expression = price * (1 - discount);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMarkdown(expression);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("Arithmetic"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("graph TD"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMarkdown_WithLogicalExpression_IncludesLogic()
|
||||
{
|
||||
// Arrange
|
||||
var expr1 = new NumberLiteralExpression(5) > new NumberLiteralExpression(3);
|
||||
var expr2 = new NumberLiteralExpression(10) < new NumberLiteralExpression(20);
|
||||
var expression = new AndExpression(expr1, expr2);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMarkdown(expression);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("AND"));
|
||||
Assert.That(result, Does.Contain("mermaid"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMarkdown_WithTitle_IncludesTitle()
|
||||
{
|
||||
// Arrange
|
||||
var expression = new StringLiteralExpression("test");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMarkdown(expression, "Test Expression");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("# Test Expression"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMarkdown_ComplexExpression_GeneratesCompleteDoc()
|
||||
{
|
||||
// Arrange
|
||||
Expression quantity = new NumberLiteralExpression(10);
|
||||
Expression price = new NumberLiteralExpression(25.50m);
|
||||
Expression discount = new NumberLiteralExpression(0.15m);
|
||||
var expression = quantity * price * (1 - discount);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMarkdown(expression, "Order Total");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("# Order Total"));
|
||||
Assert.That(result, Does.Contain("## Expression Structure"));
|
||||
Assert.That(result, Does.Contain("## Expression Type"));
|
||||
Assert.That(result, Does.Contain("## Mermaid Diagram"));
|
||||
Assert.That(result, Does.Contain("## Mathematical Expression"));
|
||||
Assert.That(result, Does.Contain("Arithmetic"));
|
||||
Assert.That(result.Length, Is.GreaterThan(200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMathematicalExpression_WithArithmetic_GeneratesLatex()
|
||||
{
|
||||
// Arrange
|
||||
Expression a = new NumberLiteralExpression(5);
|
||||
Expression b = new NumberLiteralExpression(3);
|
||||
var expression = a + b;
|
||||
|
||||
// Act
|
||||
var result = ExpressionGenerator.GenerateMathematicalExpression(expression);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("$$"));
|
||||
Assert.That(result, Does.Contain("+"));
|
||||
Assert.That(result, Does.Contain("5"));
|
||||
Assert.That(result, Does.Contain("3"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMathematicalExpression_WithMultiplication_UsesTimesSymbol()
|
||||
{
|
||||
// Arrange
|
||||
Expression x = new NumberLiteralExpression(10);
|
||||
Expression y = new NumberLiteralExpression(20);
|
||||
var expression = x * y;
|
||||
|
||||
// Act
|
||||
var result = ExpressionGenerator.GenerateMathematicalExpression(expression);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("\\times"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMathematicalExpression_WithComparison_UsesCorrectSymbol()
|
||||
{
|
||||
// Arrange
|
||||
Expression a = new NumberLiteralExpression(10);
|
||||
Expression b = new NumberLiteralExpression(20);
|
||||
var expression = a >= b;
|
||||
|
||||
// Act
|
||||
var result = ExpressionGenerator.GenerateMathematicalExpression(expression);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("\\geq"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMathematicalExpression_WithLogicalAnd_UsesLandSymbol()
|
||||
{
|
||||
// Arrange
|
||||
var expr1 = new NumberLiteralExpression(5) > new NumberLiteralExpression(3);
|
||||
var expr2 = new NumberLiteralExpression(10) < new NumberLiteralExpression(20);
|
||||
var expression = new AndExpression(expr1, expr2);
|
||||
|
||||
// Act
|
||||
var result = ExpressionGenerator.GenerateMathematicalExpression(expression);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("\\land"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMathematicalExpression_Inline_UsesSingleDollar()
|
||||
{
|
||||
// Arrange
|
||||
var expression = new NumberLiteralExpression(42);
|
||||
|
||||
// Act
|
||||
var result = ExpressionGenerator.GenerateMathematicalExpression(expression, inline: true);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("$"));
|
||||
Assert.That(result, Does.EndWith("$"));
|
||||
Assert.That(result, Does.Not.Contain("$$"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMathematicalExpression_Block_UsesDoubleDollar()
|
||||
{
|
||||
// Arrange
|
||||
var expression = new NumberLiteralExpression(42);
|
||||
|
||||
// Act
|
||||
var result = ExpressionGenerator.GenerateMathematicalExpression(expression, inline: false);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("$$"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMathematicalExpression_ComplexArithmetic_GeneratesCorrectLatex()
|
||||
{
|
||||
// Arrange
|
||||
Expression quantity = new NumberLiteralExpression(10);
|
||||
Expression price = new NumberLiteralExpression(25);
|
||||
Expression discount = new NumberLiteralExpression(0.1m);
|
||||
var expression = quantity * price * (1 - discount);
|
||||
|
||||
// Act
|
||||
var result = ExpressionGenerator.GenerateMathematicalExpression(expression);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("\\times"));
|
||||
Assert.That(result, Does.Contain("10"));
|
||||
Assert.That(result, Does.Contain("25"));
|
||||
Assert.That(result, Does.Contain("0.1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateRawMathematicalExpression_CauchySchwarzInequality_WithDollarFormat()
|
||||
{
|
||||
// Arrange
|
||||
var latex = @"\left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)";
|
||||
|
||||
// Act
|
||||
var result = ExpressionGenerator.GenerateRawMathematicalExpression(latex, format: "dollar", inline: false);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("$$"));
|
||||
Assert.That(result, Does.EndWith("$$"));
|
||||
Assert.That(result, Does.Contain("\\sum_{k=1}^n"));
|
||||
Assert.That(result, Does.Contain("a_k b_k"));
|
||||
Assert.That(result, Does.Contain("\\leq"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateRawMathematicalExpression_CauchySchwarzInequality_WithMathFormat()
|
||||
{
|
||||
// Arrange
|
||||
var latex = @"\left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)";
|
||||
|
||||
// Act
|
||||
var result = ExpressionGenerator.GenerateRawMathematicalExpression(latex, format: "math");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("```math"));
|
||||
Assert.That(result, Does.EndWith("```"));
|
||||
Assert.That(result, Does.Contain("\\sum_{k=1}^n"));
|
||||
Assert.That(result, Does.Contain("a_k b_k"));
|
||||
Assert.That(result, Does.Contain("\\leq"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateRawMathematicalExpression_Inline_UsesSingleDollar()
|
||||
{
|
||||
// Arrange
|
||||
var latex = "E = mc^2";
|
||||
|
||||
// Act
|
||||
var result = ExpressionGenerator.GenerateRawMathematicalExpression(latex, inline: true);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("$"));
|
||||
Assert.That(result, Does.EndWith("$"));
|
||||
Assert.That(result, Does.Not.Contain("```"));
|
||||
Assert.That(result, Is.EqualTo("$E = mc^2$"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional.Logical;
|
||||
using Strata.SqlTools.SqlBreakdown.Expressions.Literals;
|
||||
using Strata.SqlTools.Markdown.Expressions;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.Expressions;
|
||||
|
||||
[TestFixture]
|
||||
public class SimpleExpressionGeneratorTests
|
||||
{
|
||||
private SimpleExpressionGenerator _generator = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_generator = new SimpleExpressionGenerator();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMarkdown_WithSimpleExpression_GeneratesSimpleDoc()
|
||||
{
|
||||
// Arrange
|
||||
var expression = new NumberLiteralExpression(42);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMarkdown(expression);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("## Expression"));
|
||||
Assert.That(result, Does.Contain("## Type Information"));
|
||||
Assert.That(result, Does.Contain("## Description"));
|
||||
Assert.That(result, Does.Contain("```sql"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMarkdown_WithTitle_IncludesTitle()
|
||||
{
|
||||
// Arrange
|
||||
var expression = new StringLiteralExpression("test");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMarkdown(expression, "Simple Expression");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("# Simple Expression"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMarkdown_IncludesDescription()
|
||||
{
|
||||
// Arrange
|
||||
Expression left = new NumberLiteralExpression(100);
|
||||
Expression right = new NumberLiteralExpression(50);
|
||||
var expression = left == right;
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMarkdown(expression);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("EqualToExpression"));
|
||||
Assert.That(result, Does.Contain("expression"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateComparisonTable_WithMultipleExpressions_GeneratesTable()
|
||||
{
|
||||
// Arrange
|
||||
var expressions = new Dictionary<string, Expression>
|
||||
{
|
||||
["Price Filter"] = new NumberLiteralExpression(100) > new NumberLiteralExpression(50),
|
||||
["Status Filter"] = new StringLiteralExpression("Active") == new StringLiteralExpression("Active"),
|
||||
["Quantity Check"] = new NumberLiteralExpression(10) <= new NumberLiteralExpression(100)
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateComparisonTable(expressions);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("| Name | Expression | Type |"));
|
||||
Assert.That(result, Does.Contain("|------|------------|------|"));
|
||||
Assert.That(result, Does.Contain("Price Filter"));
|
||||
Assert.That(result, Does.Contain("Status Filter"));
|
||||
Assert.That(result, Does.Contain("Quantity Check"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateComparisonTable_WithTitle_IncludesTitle()
|
||||
{
|
||||
// Arrange
|
||||
var expressions = new Dictionary<string, Expression>
|
||||
{
|
||||
["Test"] = new NumberLiteralExpression(1)
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateComparisonTable(expressions, "Comparison Table");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("# Comparison Table"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBulletList_WithExpressions_GeneratesList()
|
||||
{
|
||||
// Arrange
|
||||
var expressions = new List<Expression>
|
||||
{
|
||||
new NumberLiteralExpression(100),
|
||||
new StringLiteralExpression("Active"),
|
||||
new NumberLiteralExpression(5) + new NumberLiteralExpression(10)
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateBulletList(expressions);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("- `100`"));
|
||||
Assert.That(result, Does.Contain("- `'Active'`"));
|
||||
Assert.That(result, Does.Contain("- `"));
|
||||
Assert.That(result, Does.Contain("*NumberLiteralExpression*"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBulletList_WithTitle_IncludesTitle()
|
||||
{
|
||||
// Arrange
|
||||
var expressions = new List<Expression>
|
||||
{
|
||||
new NumberLiteralExpression(1)
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateBulletList(expressions, "Expression List");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("## Expression List"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateComparisonTable_WithOrExpression_GeneratesTable()
|
||||
{
|
||||
// Arrange
|
||||
var expr1 = new NumberLiteralExpression(1) > new NumberLiteralExpression(0);
|
||||
var expr2 = new NumberLiteralExpression(2) > new NumberLiteralExpression(0);
|
||||
var expressions = new Dictionary<string, Expression>
|
||||
{
|
||||
["Test"] = new OrExpression(expr1, expr2)
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateComparisonTable(expressions);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("Test"));
|
||||
Assert.That(result, Does.Contain("OrExpression"));
|
||||
Assert.That(result, Does.Contain("OR"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
using Strata.SqlTools.Breakdowns.LinqToSql;
|
||||
using Strata.SqlTools.Markdown.LinqToSql;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.LinqToSql;
|
||||
|
||||
[TestFixture]
|
||||
public class QueryBreakdownGeneratorTests
|
||||
{
|
||||
private QueryBreakdownGenerator _generator = null!;
|
||||
private TestDataContext _context = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_generator = new QueryBreakdownGenerator();
|
||||
_context = new TestDataContext();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_SimpleLinqQuery_GeneratesValidMermaid()
|
||||
{
|
||||
// Arrange
|
||||
var query = _context.Users.Where(u => u.Age > 21);
|
||||
var breakdown = LinqQueryBreakdown.Analyze(query);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(breakdown, "Simple User Query");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
Assert.That(result, Does.Contain("### Simple User Query"));
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("WHERE"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMethodChainDiagram_WithMethodCalls_ShowsChain()
|
||||
{
|
||||
// Arrange
|
||||
var query = _context.Users
|
||||
.Where(u => u.Age > 18)
|
||||
.OrderBy(u => u.Name)
|
||||
.Select(u => new { u.Id, u.Name });
|
||||
var breakdown = LinqQueryBreakdown.Analyze(query);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMethodChainDiagram(breakdown, "Method Chain");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart LR"));
|
||||
Assert.That(result, Does.Contain("### Method Chain"));
|
||||
Assert.That(result, Does.Contain("Where"));
|
||||
Assert.That(result, Does.Contain("OrderBy"));
|
||||
Assert.That(result, Does.Contain("Select"));
|
||||
Assert.That(result, Does.Contain("IQueryable"));
|
||||
Assert.That(result, Does.Contain("Result"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMethodChainDiagram_EmptyChain_ShowsBasicFlow()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new LinqQueryBreakdown("*", "Users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMethodChainDiagram(breakdown);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("IQueryable"));
|
||||
Assert.That(result, Does.Contain("Result"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCombinedDiagram_IncludesBothDiagrams()
|
||||
{
|
||||
// Arrange
|
||||
var query = _context.Users.Where(u => u.Age > 21).OrderBy(u => u.Name);
|
||||
var breakdown = LinqQueryBreakdown.Analyze(query);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateCombinedDiagram(breakdown, "User Query Analysis");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("## User Query Analysis"));
|
||||
Assert.That(result, Does.Contain("### LINQ Method Chain"));
|
||||
Assert.That(result, Does.Contain("### SQL Query Structure"));
|
||||
Assert.That(result, Does.Contain("flowchart LR"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithProjection_ShowsSelectedFields()
|
||||
{
|
||||
// Arrange
|
||||
var query = _context.Users.Select(u => new { u.Id, u.Name, u.Email });
|
||||
var breakdown = LinqQueryBreakdown.Analyze(query);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(breakdown);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_NullTitle_GeneratesWithoutTitle()
|
||||
{
|
||||
// Arrange
|
||||
var query = _context.Users;
|
||||
var breakdown = LinqQueryBreakdown.Analyze(query);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(breakdown, null);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Not.Contain("###"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
}
|
||||
}
|
||||
|
||||
// Test data context
|
||||
public class TestDataContext
|
||||
{
|
||||
public IQueryable<User> Users => new List<User>().AsQueryable();
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Email { get; set; } = string.Empty;
|
||||
public int Age { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
using Strata.SqlTools.Markdown.LinqToSql;
|
||||
using Strata.SqlTools.Breakdowns.LinqToSql;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.LinqToSql;
|
||||
|
||||
[TestFixture]
|
||||
public class SqlStatementGeneratorTests
|
||||
{
|
||||
private SqlStatementGenerator _generator = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_generator = new SqlStatementGenerator();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateLinqPipelineDiagram_BasicQuery_GeneratesSequenceDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var query = new LinqQueryBreakdown("*", "Users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateLinqPipelineDiagram(query, "User Query Pipeline");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("sequenceDiagram"));
|
||||
Assert.That(result, Does.Contain("### User Query Pipeline"));
|
||||
Assert.That(result, Does.Contain("LINQ Provider"));
|
||||
Assert.That(result, Does.Contain("Expression Tree"));
|
||||
Assert.That(result, Does.Contain("SQL Generator"));
|
||||
Assert.That(result, Does.Contain("Database"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateLinqPipelineDiagram_WithWhere_ShowsPredicateProcessing()
|
||||
{
|
||||
// Arrange
|
||||
var query = new LinqQueryBreakdown("Id, Name", "Users");
|
||||
query.AddWhereClause("Age > 21");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateLinqPipelineDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("Where Predicate"));
|
||||
Assert.That(result, Does.Contain("Expression Tree"));
|
||||
Assert.That(result, Does.Contain("SQL Generator"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateLinqPipelineDiagram_WithProjection_ShowsSelectProcessing()
|
||||
{
|
||||
// Arrange
|
||||
var query = new LinqQueryBreakdown("Id, Name, Email", "Users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateLinqPipelineDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("Select Projection"));
|
||||
Assert.That(result, Does.Contain("LINQ Provider"));
|
||||
Assert.That(result, Does.Contain("Database"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateLinqPipelineDiagram_NullTitle_GeneratesWithoutTitle()
|
||||
{
|
||||
// Arrange
|
||||
var query = new LinqQueryBreakdown("*", "Users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateLinqPipelineDiagram(query, null);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Not.Contain("###"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("sequenceDiagram"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_DelegatesToBaseClass()
|
||||
{
|
||||
// Arrange
|
||||
var query = new LinqQueryBreakdown("*", "Users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query, "Sequence Test");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("sequenceDiagram"));
|
||||
Assert.That(result, Does.Contain("### Sequence Test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateEntityRelationshipDiagram_DelegatesToBaseClass()
|
||||
{
|
||||
// Arrange
|
||||
var query = new LinqQueryBreakdown("Id, Name", "Users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateEntityRelationshipDiagram(query, "ER Test");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("erDiagram"));
|
||||
Assert.That(result, Does.Contain("### ER Test"));
|
||||
}
|
||||
}
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
using Strata.SqlTools.Breakdowns.PostgreSql;
|
||||
using Strata.SqlTools.Markdown.PostgreSql;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.PostgreSql;
|
||||
|
||||
[TestFixture]
|
||||
public class QueryBreakdownCollectionGeneratorTests
|
||||
{
|
||||
private QueryBreakdownCollection _collection = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_collection = new QueryBreakdownCollection();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_WithTitle_IncludesTitle()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("id, name", "users"));
|
||||
var title = "PostgreSQL Query Report";
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection, title);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain(title));
|
||||
Assert.That(report, Does.Contain("# PostgreSQL Query Report"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_WithMultipleQueries_GeneratesCompleteReport()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("id, name, email", "users"));
|
||||
_collection.Add(new QueryBreakdown("order_id, amount", "orders"));
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Collection Summary"));
|
||||
Assert.That(report, Does.Contain("Parameter Analysis"));
|
||||
Assert.That(report, Does.Contain("Query Composition Report"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionSummary_WithQueries_IncludesSummaryMetrics()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("id, name, email", "users"));
|
||||
_collection.Add(new QueryBreakdown("order_id, amount", "orders"));
|
||||
|
||||
// Act
|
||||
var summary = QueryBreakdownCollectionGenerator.GenerateCollectionSummary(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(summary, Does.Contain("Collection Summary"));
|
||||
Assert.That(summary, Does.Contain("Total Queries"));
|
||||
Assert.That(summary, Does.Contain("2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateParameterAnalysis_NoParameters_IndicatesNoParameters()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("id, name", "users"));
|
||||
|
||||
// Act
|
||||
var analysis = QueryBreakdownCollectionGenerator.GenerateParameterAnalysis(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(analysis, Does.Contain("Parameters"));
|
||||
Assert.That(analysis, Does.Contain("No parameters"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateParameterAnalysis_WithPositionalParameters_ShowsPostgreSqlSyntax()
|
||||
{
|
||||
// Arrange - PostgreSQL positional parameters $1, $2
|
||||
var query = new QueryBreakdown("id, name", "users", "id = $1");
|
||||
query.Parameters["1"] = 123;
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var analysis = QueryBreakdownCollectionGenerator.GenerateParameterAnalysis(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(analysis, Does.Contain("Parameter Analysis"));
|
||||
Assert.That(analysis, Does.Contain("$1"));
|
||||
Assert.That(analysis, Does.Contain("Parameter Dependency Diagram"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateParameterAnalysis_WithNamedParameters_ShowsColonSyntax()
|
||||
{
|
||||
// Arrange - PostgreSQL named parameters with :
|
||||
var query = new QueryBreakdown("id, name", "users", "id = :userId");
|
||||
query.Parameters["userId"] = 123;
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var analysis = QueryBreakdownCollectionGenerator.GenerateParameterAnalysis(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(analysis, Does.Contain("Parameter Analysis"));
|
||||
Assert.That(analysis, Does.Contain(":userId"));
|
||||
Assert.That(analysis, Does.Contain("Parameter Dependency Diagram"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateParameterDependencyDiagram_WithParameters_GeneratesMermaidDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var query1 = new QueryBreakdown("id, name", "users", "id = $1");
|
||||
var query2 = new QueryBreakdown("order_id", "orders", "user_id = $1");
|
||||
query1.Parameters["1"] = 123;
|
||||
query2.Parameters["1"] = 123;
|
||||
_collection.Add(query1);
|
||||
_collection.Add(query2);
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateParameterDependencyDiagram(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(diagram, Does.Contain("```mermaid"));
|
||||
Assert.That(diagram, Does.Contain("graph TD"));
|
||||
Assert.That(diagram, Does.Contain("$1"));
|
||||
Assert.That(diagram, Does.Contain("Query #0"));
|
||||
Assert.That(diagram, Does.Contain("Query #1"));
|
||||
Assert.That(diagram, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateQueryCompositionReport_WithQueries_IncludesAllQueryDetails()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("id, name", "users", "id > 10");
|
||||
query.GroupByClause.Clause = "region";
|
||||
query.OrderByClause.Clause = "name ASC";
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateQueryCompositionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Query Composition Report"));
|
||||
Assert.That(report, Does.Contain("Query #0"));
|
||||
Assert.That(report, Does.Contain("SELECT Clause"));
|
||||
Assert.That(report, Does.Contain("✓ Yes"));
|
||||
Assert.That(report, Does.Contain("WHERE Clause"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateQueryCompositionReport_WithCTEs_IncludesCTEList()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("id, name", "users");
|
||||
var cteQuery = new QueryBreakdown("id, name", "archive_users");
|
||||
query.AddWithClause("active_users", cteQuery);
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateQueryCompositionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("CTEs Defined"));
|
||||
Assert.That(report, Does.Contain("active_users"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateQueryCompositionReport_WithParameters_IncludesParameterValues()
|
||||
{
|
||||
// Arrange - PostgreSQL positional parameters
|
||||
var query = new QueryBreakdown("id, name", "users", "id = $1 AND status = $2");
|
||||
query.Parameters["1"] = 123;
|
||||
query.Parameters["2"] = "Active";
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateQueryCompositionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Parameters Used"));
|
||||
Assert.That(report, Does.Contain("$1"));
|
||||
Assert.That(report, Does.Contain("$2"));
|
||||
Assert.That(report, Does.Contain("123"));
|
||||
Assert.That(report, Does.Contain("Active"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithQueries_GeneratesFlowDiagram()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("id, name", "users"));
|
||||
_collection.Add(new QueryBreakdown("order_id", "orders"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(diagram, Does.Contain("```mermaid"));
|
||||
Assert.That(diagram, Does.Contain("flowchart TD"));
|
||||
Assert.That(diagram, Does.Contain("Batch Start"));
|
||||
Assert.That(diagram, Does.Contain("Query 0"));
|
||||
Assert.That(diagram, Does.Contain("Query 1"));
|
||||
Assert.That(diagram, Does.Contain("Batch Complete"));
|
||||
Assert.That(diagram, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithTransaction_IncludesBeginCommit()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("id, name", "users"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection, includeTransaction: true);
|
||||
|
||||
// Assert
|
||||
Assert.That(diagram, Does.Contain("BEGIN"));
|
||||
Assert.That(diagram, Does.Contain("COMMIT"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithQueries_ValidatesProperConnections()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("id, name", "users"));
|
||||
_collection.Add(new QueryBreakdown("order_id", "orders"));
|
||||
_collection.Add(new QueryBreakdown("product_id", "products"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection);
|
||||
|
||||
// Assert
|
||||
// Verify proper connections between nodes
|
||||
Assert.That(diagram, Does.Contain("Start([Batch Start]) --> node0")); // Start connects to first node
|
||||
Assert.That(diagram, Does.Contain("node0[\"Query 0\"] --> node1")); // Query 0 to Query 1
|
||||
Assert.That(diagram, Does.Contain("node1[\"Query 1\"] --> node2")); // Query 1 to Query 2
|
||||
Assert.That(diagram, Does.Contain("node2[\"Query 2\"] --> End")); // Last query connects to End
|
||||
// Verify no dangling nodes
|
||||
Assert.That(diagram, Does.Not.Contain("node3")); // No extra unconnected node
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithTransaction_ValidatesProperConnections()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("id, name", "users"));
|
||||
_collection.Add(new QueryBreakdown("order_id", "orders"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection, includeTransaction: true);
|
||||
|
||||
// Assert
|
||||
// Verify proper transaction flow
|
||||
Assert.That(diagram, Does.Contain("Start([Batch Start]) --> node0")); // Start connects to BEGIN
|
||||
Assert.That(diagram, Does.Contain("node0[\"BEGIN\"]")); // BEGIN node
|
||||
Assert.That(diagram, Does.Contain("node0 --> node1")); // BEGIN to first query
|
||||
Assert.That(diagram, Does.Contain("node1[\"Query 0\"] --> node2")); // Query 0 to Query 1
|
||||
Assert.That(diagram, Does.Contain("node2[\"Query 1\"] --> node3")); // Last query to COMMIT
|
||||
Assert.That(diagram, Does.Contain("node3[\"COMMIT\"]")); // COMMIT node
|
||||
Assert.That(diagram, Does.Contain("node3 --> End")); // COMMIT to End
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_EmptyCollection_GeneratesValidMarkdown()
|
||||
{
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Collection Summary"));
|
||||
Assert.That(report, Does.Contain("Parameter Analysis"));
|
||||
Assert.That(report, Does.Contain("Total Queries"));
|
||||
Assert.That(report, Does.Contain("0"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_WithMultipleQueries_ContainsAllSections()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("id, name", "users"));
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("## Collection Summary"));
|
||||
Assert.That(report, Does.Contain("## Parameter Analysis"));
|
||||
Assert.That(report, Does.Contain("## Query Composition Report"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_EmptyCollection_GeneratesValidDiagram()
|
||||
{
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(diagram, Does.Contain("```mermaid"));
|
||||
Assert.That(diagram, Does.Contain("flowchart TD"));
|
||||
Assert.That(diagram, Does.Contain("Batch Start"));
|
||||
Assert.That(diagram, Does.Contain("Batch Complete"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_EmptyCollectionWithTransaction_IncludesTransactionNodes()
|
||||
{
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection, includeTransaction: true);
|
||||
|
||||
// Assert
|
||||
Assert.That(diagram, Does.Contain("BEGIN"));
|
||||
Assert.That(diagram, Does.Contain("COMMIT"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
using Strata.SqlTools.Breakdowns.PostgreSql;
|
||||
using Strata.SqlTools.Markdown.PostgreSql;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.PostgreSql;
|
||||
|
||||
[TestFixture]
|
||||
public class QueryBreakdownGeneratorTests
|
||||
{
|
||||
private QueryBreakdownGenerator _generator = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_generator = new QueryBreakdownGenerator();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_SimplePostgreSqlQuery_GeneratesValidMermaid()
|
||||
{
|
||||
// Arrange - Using PostgreSQL syntax with lowercase identifiers
|
||||
var query = new QueryBreakdown("user_id, user_name", "users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "Simple User Query");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
Assert.That(result, Does.Contain("### Simple User Query"));
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithPositionalParameters_HandlesParameters()
|
||||
{
|
||||
// Arrange - PostgreSQL uses $1, $2 syntax for positional parameters
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT user_id, user_name, status
|
||||
FROM users
|
||||
WHERE user_id = $1
|
||||
AND status = $2
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("WHERE"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithNamedParameters_HandlesColonSyntax()
|
||||
{
|
||||
// Arrange - PostgreSQL also supports :parameter syntax
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT user_id, user_name, email
|
||||
FROM users
|
||||
WHERE user_id = :userId
|
||||
AND status = :status
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("WHERE"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithPostgreSqlCTE_ShowsWithClause()
|
||||
{
|
||||
// Arrange - PostgreSQL CTE with lowercase naming
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
WITH active_users AS (
|
||||
SELECT user_id, user_name
|
||||
FROM users
|
||||
WHERE status = 'ACTIVE'
|
||||
)
|
||||
SELECT u.user_id, u.user_name, COUNT(o.order_id) AS order_count
|
||||
FROM active_users u
|
||||
JOIN orders o ON u.user_id = o.user_id
|
||||
GROUP BY u.user_id, u.user_name
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "Users with Orders");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("### Users with Orders"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
Assert.That(result, Does.Contain("GROUP BY"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithLimit_HandlesLimitClause()
|
||||
{
|
||||
// Arrange - PostgreSQL LIMIT clause
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT user_id, user_name, created_at
|
||||
FROM users
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 10
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "Recent Users");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("ORDER BY"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithLimitOffset_HandlesPagination()
|
||||
{
|
||||
// Arrange - PostgreSQL LIMIT/OFFSET for pagination
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT product_id, product_name, price
|
||||
FROM products
|
||||
ORDER BY product_name
|
||||
LIMIT 20 OFFSET 40
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("ORDER BY"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithDoubleQuotedIdentifiers_HandlesPostgreSqlQuoting()
|
||||
{
|
||||
// Arrange - PostgreSQL uses "identifier" for case-sensitive names
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT ""userId"", ""userName"", ""emailAddress""
|
||||
FROM ""Users""
|
||||
WHERE ""status"" = 'ACTIVE'
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("WHERE"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_ComplexPostgreSqlQuery_GeneratesCompleteDiagram()
|
||||
{
|
||||
// Arrange - Complex PostgreSQL query with multiple clauses
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
WITH sales_data AS (
|
||||
SELECT
|
||||
region,
|
||||
product_id,
|
||||
SUM(sales_amount) AS total_sales,
|
||||
COUNT(*) AS order_count
|
||||
FROM sales
|
||||
WHERE sale_date >= $1 AND sale_date <= $2
|
||||
GROUP BY region, product_id
|
||||
)
|
||||
SELECT
|
||||
sd.region,
|
||||
p.product_name,
|
||||
sd.total_sales,
|
||||
sd.order_count
|
||||
FROM sales_data sd
|
||||
JOIN products p ON sd.product_id = p.product_id
|
||||
WHERE sd.total_sales > $3
|
||||
ORDER BY sd.total_sales DESC
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "Regional Sales Analysis");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("### Regional Sales Analysis"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("WHERE"));
|
||||
Assert.That(result, Does.Contain("ORDER BY"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithGroupByAndHaving_IncludesBothClauses()
|
||||
{
|
||||
// Arrange
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT category, COUNT(*) AS product_count, AVG(price) AS avg_price
|
||||
FROM products
|
||||
GROUP BY category
|
||||
HAVING COUNT(*) > 10 AND AVG(price) < 100
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("GROUP BY"));
|
||||
Assert.That(result, Does.Contain("HAVING"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_NullTitle_GeneratesWithoutTitle()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("id", "orders");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, null);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Not.Contain("###"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_EmptyTitle_GeneratesWithoutTitle()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("order_id", "orders");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Not.Contain("###"));
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_PostgreSqlTypeCasting_PreservesSyntax()
|
||||
{
|
||||
// Arrange - PostgreSQL :: casting syntax
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT
|
||||
order_id::VARCHAR AS order_code,
|
||||
amount::DECIMAL(10,2) AS formatted_amount,
|
||||
create_date::TIMESTAMP AS created_at
|
||||
FROM orders
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "Type Cast Example");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("### Type Cast Example"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_PostgreSqlJsonOperators_HandlesJsonNotation()
|
||||
{
|
||||
// Arrange - PostgreSQL JSON operators (-> for JSON object, ->> for text)
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT
|
||||
json_data->>'name' AS name,
|
||||
json_data->'address'->>'city' AS city,
|
||||
(json_data->>'age')::INTEGER AS age
|
||||
FROM user_json
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "JSON Data");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithDistinct_HandlesDistinctClause()
|
||||
{
|
||||
// Arrange - PostgreSQL DISTINCT
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT DISTINCT region, product_category
|
||||
FROM sales
|
||||
ORDER BY region, product_category
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("ORDER BY"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using Strata.SqlTools.Breakdowns.PostgreSql;
|
||||
using Strata.SqlTools.Markdown.PostgreSql;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.PostgreSql;
|
||||
|
||||
[TestFixture]
|
||||
public class SqlStatementGeneratorTests
|
||||
{
|
||||
private SqlStatementGenerator _generator = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_generator = new SqlStatementGenerator();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_PostgreSqlQuery_GeneratesValidDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT user_id, user_name, email
|
||||
FROM users
|
||||
WHERE status = 'ACTIVE'
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query, "User Query Flow");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("sequenceDiagram"));
|
||||
Assert.That(result, Does.Contain("### User Query Flow"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_WithPostgreSqlCTE_ShowsMainStatement()
|
||||
{
|
||||
// Arrange
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
WITH active_customers AS (
|
||||
SELECT customer_id, customer_name
|
||||
FROM customers
|
||||
WHERE status = 'ACTIVE'
|
||||
)
|
||||
SELECT c.customer_id, c.customer_name, COUNT(o.order_id) AS order_count
|
||||
FROM active_customers c
|
||||
LEFT JOIN orders o ON c.customer_id = o.customer_id
|
||||
GROUP BY c.customer_id, c.customer_name
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("Execute Main Statement"));
|
||||
Assert.That(result, Does.Contain("activate DB"));
|
||||
Assert.That(result, Does.Contain("deactivate DB"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_ComplexPostgreSqlQuery_GeneratesSequenceDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT region, product, SUM(sales) AS total_sales
|
||||
FROM sales_data
|
||||
WHERE sale_date >= $1
|
||||
GROUP BY region, product
|
||||
HAVING SUM(sales) > 1000
|
||||
ORDER BY total_sales DESC
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query, "Sales Analysis");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("### Sales Analysis"));
|
||||
Assert.That(result, Does.Contain("sequenceDiagram"));
|
||||
Assert.That(result, Does.Contain("Execute Main Statement"));
|
||||
Assert.That(result, Does.Contain("activate DB"));
|
||||
Assert.That(result, Does.Contain("Return Results"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateEntityRelationshipDiagram_PostgreSqlTables_GeneratesERDiagram()
|
||||
{
|
||||
// Arrange - PostgreSQL typically uses lowercase table names
|
||||
var tables = new[] { "customers", "orders", "order_items", "products" };
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateEntityRelationshipDiagram(tables, "E-Commerce Schema");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("erDiagram"));
|
||||
Assert.That(result, Does.Contain("### E-Commerce Schema"));
|
||||
Assert.That(result, Does.Contain("customers"));
|
||||
Assert.That(result, Does.Contain("orders"));
|
||||
Assert.That(result, Does.Contain("order_items"));
|
||||
Assert.That(result, Does.Contain("products"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateEntityRelationshipDiagram_WithDoubleQuotedNames_HandlesQuotedIdentifiers()
|
||||
{
|
||||
// Arrange - PostgreSQL case-sensitive identifiers
|
||||
var tables = new[] { "\"Customers\"", "\"Orders\"", "\"OrderItems\"" };
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateEntityRelationshipDiagram(tables);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("erDiagram"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateEntityRelationshipDiagram_WithSchemaQualifiedNames_HandlesSchemaDotTable()
|
||||
{
|
||||
// Arrange - PostgreSQL schema.table qualified names
|
||||
var tables = new[] { "public.users", "sales.orders", "inventory.products" };
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateEntityRelationshipDiagram(tables);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("erDiagram"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateEntityRelationshipDiagram_SingleTable_GeneratesDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var tables = new[] { "users" };
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateEntityRelationshipDiagram(tables);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("erDiagram"));
|
||||
Assert.That(result, Does.Contain("users"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_NullTitle_GeneratesWithoutTitle()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("order_id", "orders");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query, null);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Not.Contain("###"));
|
||||
Assert.That(result, Does.Contain("sequenceDiagram"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_WithPositionalParameters_HandlesParametrizedQuery()
|
||||
{
|
||||
// Arrange - PostgreSQL positional parameters $1, $2
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT product_id, product_name, price
|
||||
FROM products
|
||||
WHERE category_id = $1 AND price > $2
|
||||
ORDER BY price DESC
|
||||
");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("sequenceDiagram"));
|
||||
Assert.That(result, Does.Contain("Execute Main Statement"));
|
||||
}
|
||||
}
|
||||
+327
@@ -0,0 +1,327 @@
|
||||
using Strata.SqlTools.Breakdowns.Snowflake;
|
||||
using Strata.SqlTools.Markdown.Snowflake;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.Snowflake;
|
||||
|
||||
[TestFixture]
|
||||
public class QueryBreakdownCollectionGeneratorTests
|
||||
{
|
||||
private QueryBreakdownCollection _collection = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_collection = new QueryBreakdownCollection();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_WithTitle_IncludesTitle()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
var title = "Snowflake Query Report";
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection, title);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain(title));
|
||||
Assert.That(report, Does.Contain("# Snowflake Query Report"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_WithMultipleQueries_GeneratesCompleteReport()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name, Email", "Users"));
|
||||
_collection.Add(new QueryBreakdown("OrderID, Amount", "Orders"));
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Collection Summary"));
|
||||
Assert.That(report, Does.Contain("Snowflake Features"));
|
||||
Assert.That(report, Does.Contain("Parameter Analysis"));
|
||||
Assert.That(report, Does.Contain("Query Composition Report"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionSummary_WithQueries_IncludesSummaryMetrics()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name, Email", "Users"));
|
||||
_collection.Add(new QueryBreakdown("OrderID, Amount", "Orders"));
|
||||
|
||||
// Act
|
||||
var summary = QueryBreakdownCollectionGenerator.GenerateCollectionSummary(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(summary, Does.Contain("Collection Summary"));
|
||||
Assert.That(summary, Does.Contain("Total Queries"));
|
||||
Assert.That(summary, Does.Contain("2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSnowflakeFeaturesAnalysis_WithStageReferences_ReportsUsage()
|
||||
{
|
||||
// Arrange
|
||||
var stageQuery = new QueryBreakdown("$1, $2", "@mystage/data.csv");
|
||||
_collection.Add(stageQuery);
|
||||
|
||||
// Act
|
||||
var analysis = QueryBreakdownCollectionGenerator.GenerateSnowflakeFeaturesAnalysis(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(analysis, Does.Contain("Snowflake Features"));
|
||||
Assert.That(analysis, Does.Contain("Stage References"));
|
||||
Assert.That(analysis, Does.Contain("✓ Yes"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSnowflakeFeaturesAnalysis_WithSemiStructuredData_ReportsUsage()
|
||||
{
|
||||
// Arrange
|
||||
var jsonQuery = new QueryBreakdown("JSON_EXTRACT(data, '$.id')", "raw_data");
|
||||
_collection.Add(jsonQuery);
|
||||
|
||||
// Act
|
||||
var analysis = QueryBreakdownCollectionGenerator.GenerateSnowflakeFeaturesAnalysis(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(analysis, Does.Contain("Semi-Structured Data"));
|
||||
Assert.That(analysis, Does.Contain("✓ Yes"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateParameterAnalysis_NoParameters_IndicatesNoParameters()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
|
||||
// Act
|
||||
var analysis = QueryBreakdownCollectionGenerator.GenerateParameterAnalysis(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(analysis, Does.Contain("Parameters"));
|
||||
Assert.That(analysis, Does.Contain("No parameters"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateParameterAnalysis_WithParameters_ShowsSnowflakeSyntax()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ID, Name", "Users", "ID = :UserId");
|
||||
query.Parameters["UserId"] = 123;
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var analysis = QueryBreakdownCollectionGenerator.GenerateParameterAnalysis(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(analysis, Does.Contain("Parameter Analysis"));
|
||||
Assert.That(analysis, Does.Contain(":UserId"));
|
||||
Assert.That(analysis, Does.Contain("@UserId")); // Snowflake supports both
|
||||
Assert.That(analysis, Does.Contain("Parameter Dependency Diagram"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateParameterDependencyDiagram_WithParameters_GeneratesMermaidDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var query1 = new QueryBreakdown("ID, Name", "Users", "ID = :UserId");
|
||||
var query2 = new QueryBreakdown("OrderID", "Orders", "UserID = :UserId");
|
||||
query1.Parameters["UserId"] = 123;
|
||||
query2.Parameters["UserId"] = 123;
|
||||
_collection.Add(query1);
|
||||
_collection.Add(query2);
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateParameterDependencyDiagram(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(diagram, Does.Contain("```mermaid"));
|
||||
Assert.That(diagram, Does.Contain("graph TD"));
|
||||
Assert.That(diagram, Does.Contain(":UserId"));
|
||||
Assert.That(diagram, Does.Contain("Query #0"));
|
||||
Assert.That(diagram, Does.Contain("Query #1"));
|
||||
Assert.That(diagram, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateQueryCompositionReport_WithQueries_IncludesAllQueryDetails()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ID, Name", "Users", "ID > 10");
|
||||
query.GroupByClause.Clause = "Region";
|
||||
query.OrderByClause.Clause = "Name ASC";
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateQueryCompositionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Query Composition Report"));
|
||||
Assert.That(report, Does.Contain("Query #0"));
|
||||
Assert.That(report, Does.Contain("SELECT Clause"));
|
||||
Assert.That(report, Does.Contain("✓ Yes"));
|
||||
Assert.That(report, Does.Contain("WHERE Clause"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateQueryCompositionReport_WithSnowflakeFeatures_IncludesFeatureInfo()
|
||||
{
|
||||
// Arrange
|
||||
var jsonQuery = new QueryBreakdown("JSON_EXTRACT(data, '$.id')", "raw_data");
|
||||
var stageQuery = new QueryBreakdown("$1, $2", "@mystage/data.csv");
|
||||
_collection.Add(jsonQuery);
|
||||
_collection.Add(stageQuery);
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateQueryCompositionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Snowflake Features"));
|
||||
Assert.That(report, Does.Contain("Semi-Structured Data"));
|
||||
Assert.That(report, Does.Contain("Stage References"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateQueryCompositionReport_WithCTEs_IncludesCTEList()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ID, Name", "Users");
|
||||
var cteQuery = new QueryBreakdown("ID, Name", "ArchiveUsers");
|
||||
query.AddWithClause("ActiveUsers", cteQuery);
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateQueryCompositionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("CTEs Defined"));
|
||||
Assert.That(report, Does.Contain("ActiveUsers"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateQueryCompositionReport_WithParameters_IncludesParameterValues()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ID, Name", "Users", "ID = :UserId AND Status = :Status");
|
||||
query.Parameters["UserId"] = 123;
|
||||
query.Parameters["Status"] = "Active";
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateQueryCompositionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Parameters Used"));
|
||||
Assert.That(report, Does.Contain(":UserId"));
|
||||
Assert.That(report, Does.Contain(":Status"));
|
||||
Assert.That(report, Does.Contain("123"));
|
||||
Assert.That(report, Does.Contain("Active"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithQueries_GeneratesFlowDiagram()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
_collection.Add(new QueryBreakdown("OrderID", "Orders"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(diagram, Does.Contain("```mermaid"));
|
||||
Assert.That(diagram, Does.Contain("flowchart TD"));
|
||||
Assert.That(diagram, Does.Contain("Batch Start"));
|
||||
Assert.That(diagram, Does.Contain("Query 0"));
|
||||
Assert.That(diagram, Does.Contain("Query 1"));
|
||||
Assert.That(diagram, Does.Contain("Batch Complete"));
|
||||
Assert.That(diagram, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithSessionSetup_IncludesSessionSetup()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection, includeSessionSetup: true);
|
||||
|
||||
// Assert
|
||||
Assert.That(diagram, Does.Contain("Session Setup"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithQueries_ValidatesProperConnections()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
_collection.Add(new QueryBreakdown("OrderID", "Orders"));
|
||||
_collection.Add(new QueryBreakdown("ProductID", "Products"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection);
|
||||
|
||||
// Assert
|
||||
// Verify proper connections between nodes
|
||||
Assert.That(diagram, Does.Contain("Start([Batch Start]) --> node0")); // Start connects to first node
|
||||
Assert.That(diagram, Does.Contain("node0[\"Query 0\"] --> node1")); // Query 0 to Query 1
|
||||
Assert.That(diagram, Does.Contain("node1[\"Query 1\"] --> node2")); // Query 1 to Query 2
|
||||
Assert.That(diagram, Does.Contain("node2[\"Query 2\"] --> End")); // Last query connects to End
|
||||
// Verify no dangling nodes
|
||||
Assert.That(diagram, Does.Not.Contain("node3")); // No extra unconnected node
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithSessionSetup_ValidatesProperConnections()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
_collection.Add(new QueryBreakdown("OrderID", "Orders"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection, includeSessionSetup: true);
|
||||
|
||||
// Assert
|
||||
// Verify proper session setup flow
|
||||
Assert.That(diagram, Does.Contain("Start([Batch Start]) --> node0")); // Start connects to Session Setup
|
||||
Assert.That(diagram, Does.Contain("node0[\"Session Setup\"]")); // Session Setup node
|
||||
Assert.That(diagram, Does.Contain("node0 --> node1")); // Session Setup to first query
|
||||
Assert.That(diagram, Does.Contain("node1[\"Query 0\"] --> node2")); // Query 0 to Query 1
|
||||
Assert.That(diagram, Does.Contain("node2[\"Query 1\"] --> End")); // Last query to End
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_EmptyCollection_GeneratesValidMarkdown()
|
||||
{
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Collection Summary"));
|
||||
Assert.That(report, Does.Contain("Snowflake Features"));
|
||||
Assert.That(report, Does.Contain("Total Queries"));
|
||||
Assert.That(report, Does.Contain("0"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_WithSnowflakeSpecific_ContainsAllSections()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("## Collection Summary"));
|
||||
Assert.That(report, Does.Contain("## Snowflake Features"));
|
||||
Assert.That(report, Does.Contain("## Parameter Analysis"));
|
||||
Assert.That(report, Does.Contain("## Query Composition Report"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
using Strata.SqlTools.Breakdowns.Snowflake;
|
||||
using Strata.SqlTools.Markdown.Snowflake;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.Snowflake;
|
||||
|
||||
[TestFixture]
|
||||
public class QueryBreakdownGeneratorTests
|
||||
{
|
||||
private QueryBreakdownGenerator _generator = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_generator = new QueryBreakdownGenerator();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_SimpleSnowflakeQuery_GeneratesValidMermaid()
|
||||
{
|
||||
// Arrange - Using Snowflake syntax with uppercase identifiers
|
||||
var query = new QueryBreakdown("USER_ID, USER_NAME", "USERS");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "Simple User Query");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
Assert.That(result, Does.Contain("### Simple User Query"));
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithSnowflakeColonParameters_HandlesParameters()
|
||||
{
|
||||
// Arrange - Snowflake uses :parameter syntax
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT USER_ID, USER_NAME, STATUS
|
||||
FROM USERS
|
||||
WHERE USER_ID = :userId
|
||||
AND STATUS = :status
|
||||
", isMicrosoftSql: false);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("WHERE"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithSnowflakeCTE_ShowsWithClause()
|
||||
{
|
||||
// Arrange - Snowflake CTE with uppercase naming
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
WITH ACTIVE_USERS AS (
|
||||
SELECT USER_ID, USER_NAME
|
||||
FROM USERS
|
||||
WHERE STATUS = 'ACTIVE'
|
||||
)
|
||||
SELECT U.USER_ID, U.USER_NAME, COUNT(O.ORDER_ID) AS ORDER_COUNT
|
||||
FROM ACTIVE_USERS U
|
||||
JOIN ORDERS O ON U.USER_ID = O.USER_ID
|
||||
GROUP BY U.USER_ID, U.USER_NAME
|
||||
", isMicrosoftSql: false);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "Users with Orders");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("WITH Clause"));
|
||||
Assert.That(result, Does.Contain("ACTIVE_USERS"));
|
||||
Assert.That(result, Does.Contain("GROUP BY"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithSnowflakeQualify_HandlesQualifyClause()
|
||||
{
|
||||
// Arrange - Snowflake QUALIFY clause (window function filtering)
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT
|
||||
CUSTOMER_ID,
|
||||
ORDER_DATE,
|
||||
ORDER_AMOUNT,
|
||||
ROW_NUMBER() OVER (PARTITION BY CUSTOMER_ID ORDER BY ORDER_DATE DESC) AS RN
|
||||
FROM ORDERS
|
||||
QUALIFY RN = 1
|
||||
", isMicrosoftSql: false);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "Latest Orders per Customer");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithDoubleQuotedIdentifiers_HandlesSnowflakeQuoting()
|
||||
{
|
||||
// Arrange - Snowflake uses "identifier" for case-sensitive names
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT ""userId"", ""userName"", ""emailAddress""
|
||||
FROM ""Users""
|
||||
WHERE ""status"" = 'ACTIVE'
|
||||
", isMicrosoftSql: false);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("WHERE"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_ComplexSnowflakeQuery_GeneratesCompleteDiagram()
|
||||
{
|
||||
// Arrange - Complex Snowflake query with multiple clauses
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
WITH SALES_DATA AS (
|
||||
SELECT
|
||||
REGION,
|
||||
PRODUCT_ID,
|
||||
SUM(SALES_AMOUNT) AS TOTAL_SALES,
|
||||
COUNT(*) AS ORDER_COUNT
|
||||
FROM SALES
|
||||
WHERE SALE_DATE >= :startDate AND SALE_DATE <= :endDate
|
||||
GROUP BY REGION, PRODUCT_ID
|
||||
)
|
||||
SELECT
|
||||
SD.REGION,
|
||||
P.PRODUCT_NAME,
|
||||
SD.TOTAL_SALES,
|
||||
SD.ORDER_COUNT
|
||||
FROM SALES_DATA SD
|
||||
JOIN PRODUCTS P ON SD.PRODUCT_ID = P.PRODUCT_ID
|
||||
WHERE SD.TOTAL_SALES > :minSales
|
||||
ORDER BY SD.TOTAL_SALES DESC
|
||||
", isMicrosoftSql: false);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "Regional Sales Analysis");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("### Regional Sales Analysis"));
|
||||
Assert.That(result, Does.Contain("WITH Clause"));
|
||||
Assert.That(result, Does.Contain("SALES_DATA"));
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("WHERE"));
|
||||
Assert.That(result, Does.Contain("ORDER BY"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithGroupByAndHaving_IncludesBothClauses()
|
||||
{
|
||||
// Arrange
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT CATEGORY, COUNT(*) AS PRODUCT_COUNT, AVG(PRICE) AS AVG_PRICE
|
||||
FROM PRODUCTS
|
||||
GROUP BY CATEGORY
|
||||
HAVING COUNT(*) > 10 AND AVG(PRICE) < 100
|
||||
", isMicrosoftSql: false);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("GROUP BY"));
|
||||
Assert.That(result, Does.Contain("HAVING"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_NullTitle_GeneratesWithoutTitle()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ID", "ORDERS");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, null);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Not.Contain("###"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_EmptyTitle_GeneratesWithoutTitle()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ORDER_ID", "ORDERS");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Not.Contain("###"));
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_SnowflakeTypeCasting_PreservesSyntax()
|
||||
{
|
||||
// Arrange - Snowflake :: casting syntax
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT
|
||||
ORDER_ID::VARCHAR AS ORDER_CODE,
|
||||
AMOUNT::DECIMAL(10,2) AS FORMATTED_AMOUNT,
|
||||
CREATE_DATE::TIMESTAMP AS CREATED_AT
|
||||
FROM ORDERS
|
||||
", isMicrosoftSql: false);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "Type Cast Example");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("### Type Cast Example"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_SnowflakeJsonPath_HandlesJsonNotation()
|
||||
{
|
||||
// Arrange - Snowflake JSON path notation (: for path access)
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT
|
||||
JSON_DATA:name::STRING AS NAME,
|
||||
JSON_DATA:address.city::STRING AS CITY,
|
||||
JSON_DATA:age::NUMBER AS AGE
|
||||
FROM USER_JSON
|
||||
", isMicrosoftSql: false);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "JSON Data");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
using Strata.SqlTools.Breakdowns.Snowflake;
|
||||
using Strata.SqlTools.Markdown.Snowflake;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.Snowflake;
|
||||
|
||||
[TestFixture]
|
||||
public class SqlStatementGeneratorTests
|
||||
{
|
||||
private SqlStatementGenerator _generator = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_generator = new SqlStatementGenerator();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_SnowflakeQuery_GeneratesValidDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT USER_ID, USER_NAME, EMAIL
|
||||
FROM USERS
|
||||
WHERE STATUS = 'ACTIVE'
|
||||
", isMicrosoftSql: false);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query, "User Query Flow");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("sequenceDiagram"));
|
||||
Assert.That(result, Does.Contain("### User Query Flow"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_WithSnowflakeCTE_ShowsMainStatement()
|
||||
{
|
||||
// Arrange
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
WITH ACTIVE_CUSTOMERS AS (
|
||||
SELECT CUSTOMER_ID, CUSTOMER_NAME
|
||||
FROM CUSTOMERS
|
||||
WHERE STATUS = 'ACTIVE'
|
||||
)
|
||||
SELECT C.CUSTOMER_ID, C.CUSTOMER_NAME, COUNT(O.ORDER_ID) AS ORDER_COUNT
|
||||
FROM ACTIVE_CUSTOMERS C
|
||||
LEFT JOIN ORDERS O ON C.CUSTOMER_ID = O.CUSTOMER_ID
|
||||
GROUP BY C.CUSTOMER_ID, C.CUSTOMER_NAME
|
||||
", isMicrosoftSql: false);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("Execute Main Statement"));
|
||||
Assert.That(result, Does.Contain("activate DB"));
|
||||
Assert.That(result, Does.Contain("deactivate DB"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_ComplexSnowflakeQuery_GeneratesSequenceDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var query = QueryBreakdown.Parse(@"
|
||||
SELECT REGION, PRODUCT, SUM(SALES) AS TOTAL_SALES
|
||||
FROM SALES_DATA
|
||||
WHERE SALE_DATE >= :startDate
|
||||
GROUP BY REGION, PRODUCT
|
||||
HAVING SUM(SALES) > 1000
|
||||
ORDER BY TOTAL_SALES DESC
|
||||
", isMicrosoftSql: false);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query, "Sales Analysis");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("### Sales Analysis"));
|
||||
Assert.That(result, Does.Contain("sequenceDiagram"));
|
||||
Assert.That(result, Does.Contain("Execute Main Statement"));
|
||||
Assert.That(result, Does.Contain("activate DB"));
|
||||
Assert.That(result, Does.Contain("Return Results"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateEntityRelationshipDiagram_SnowflakeTables_GeneratesERDiagram()
|
||||
{
|
||||
// Arrange - Snowflake typically uses uppercase table names
|
||||
var tables = new[] { "CUSTOMERS", "ORDERS", "ORDER_ITEMS", "PRODUCTS" };
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateEntityRelationshipDiagram(tables, "E-Commerce Schema");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("erDiagram"));
|
||||
Assert.That(result, Does.Contain("### E-Commerce Schema"));
|
||||
Assert.That(result, Does.Contain("CUSTOMERS"));
|
||||
Assert.That(result, Does.Contain("ORDERS"));
|
||||
Assert.That(result, Does.Contain("ORDER_ITEMS"));
|
||||
Assert.That(result, Does.Contain("PRODUCTS"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateEntityRelationshipDiagram_WithDoubleQuotedNames_HandlesQuotedIdentifiers()
|
||||
{
|
||||
// Arrange - Snowflake case-sensitive identifiers
|
||||
var tables = new[] { "\"customers\"", "\"orders\"", "\"orderItems\"" };
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateEntityRelationshipDiagram(tables);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("erDiagram"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateEntityRelationshipDiagram_SingleTable_GeneratesDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var tables = new[] { "USERS" };
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateEntityRelationshipDiagram(tables);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("erDiagram"));
|
||||
Assert.That(result, Does.Contain("USERS"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_NullTitle_GeneratesWithoutTitle()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ORDER_ID", "ORDERS");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query, null);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Not.Contain("###"));
|
||||
Assert.That(result, Does.Contain("sequenceDiagram"));
|
||||
}
|
||||
}
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
using Strata.SqlTools.Breakdowns.SqlServer;
|
||||
using Strata.SqlTools.Markdown.SqlServer;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.SqlServer;
|
||||
|
||||
[TestFixture]
|
||||
public class QueryBreakdownCollectionGeneratorTests
|
||||
{
|
||||
private QueryBreakdownCollection _collection = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_collection = new QueryBreakdownCollection();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_WithTitle_IncludesTitle()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
var title = "User Query Report";
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection, title);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain(title));
|
||||
Assert.That(report, Does.Contain("# User Query Report"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_WithMultipleQueries_GeneratesCompleteReport()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name, Email", "Users"));
|
||||
_collection.Add(new QueryBreakdown("OrderID, Amount", "Orders"));
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Collection Summary"));
|
||||
Assert.That(report, Does.Contain("Parameter Analysis"));
|
||||
Assert.That(report, Does.Contain("Query Composition Report"));
|
||||
Assert.That(report, Does.Contain("Total Queries"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionSummary_WithQueries_IncludesSummaryMetrics()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name, Email", "Users"));
|
||||
_collection.Add(new QueryBreakdown("OrderID, Amount", "Orders"));
|
||||
|
||||
// Act
|
||||
var summary = QueryBreakdownCollectionGenerator.GenerateCollectionSummary(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(summary, Does.Contain("Collection Summary"));
|
||||
Assert.That(summary, Does.Contain("Total Queries"));
|
||||
Assert.That(summary, Does.Contain("2"));
|
||||
Assert.That(summary, Does.Contain("Unique Tables"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateParameterAnalysis_NoParameters_IndicatesNoParameters()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
|
||||
// Act
|
||||
var analysis = QueryBreakdownCollectionGenerator.GenerateParameterAnalysis(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(analysis, Does.Contain("Parameters"));
|
||||
Assert.That(analysis, Does.Contain("No parameters"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateParameterAnalysis_WithParameters_IncludesParameterTable()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ID, Name", "Users", "ID = @UserId");
|
||||
query.Parameters["UserId"] = 123;
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var analysis = QueryBreakdownCollectionGenerator.GenerateParameterAnalysis(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(analysis, Does.Contain("Parameter Analysis"));
|
||||
Assert.That(analysis, Does.Contain("@UserId"));
|
||||
Assert.That(analysis, Does.Contain("Parameter Dependency Diagram"));
|
||||
Assert.That(analysis, Does.Contain("```mermaid"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateParameterDependencyDiagram_WithParameters_GeneratesMermaidDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var query1 = new QueryBreakdown("ID, Name", "Users", "ID = @UserId");
|
||||
var query2 = new QueryBreakdown("OrderID", "Orders", "UserID = @UserId");
|
||||
query1.Parameters["UserId"] = 123;
|
||||
query2.Parameters["UserId"] = 123;
|
||||
_collection.Add(query1);
|
||||
_collection.Add(query2);
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateParameterDependencyDiagram(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(diagram, Does.Contain("```mermaid"));
|
||||
Assert.That(diagram, Does.Contain("graph TD"));
|
||||
Assert.That(diagram, Does.Contain("@UserId"));
|
||||
Assert.That(diagram, Does.Contain("Query #0"));
|
||||
Assert.That(diagram, Does.Contain("Query #1"));
|
||||
Assert.That(diagram, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateQueryCompositionReport_WithQueries_IncludesAllQueryDetails()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ID, Name", "Users", "ID > 10");
|
||||
query.GroupByClause.Clause = "Region";
|
||||
query.OrderByClause.Clause = "Name ASC";
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateQueryCompositionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Query Composition Report"));
|
||||
Assert.That(report, Does.Contain("Query #0"));
|
||||
Assert.That(report, Does.Contain("SELECT Clause"));
|
||||
Assert.That(report, Does.Contain("✓ Yes"));
|
||||
Assert.That(report, Does.Contain("WHERE Clause"));
|
||||
Assert.That(report, Does.Contain("GROUP BY"));
|
||||
Assert.That(report, Does.Contain("ORDER BY"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateQueryCompositionReport_WithCTEs_IncludesCTEList()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ID, Name", "Users");
|
||||
var cteQuery = new QueryBreakdown("ID, Name", "ArchiveUsers");
|
||||
query.AddWithClause("ActiveUsers", cteQuery);
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateQueryCompositionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("CTEs Defined"));
|
||||
Assert.That(report, Does.Contain("ActiveUsers"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateQueryCompositionReport_WithParameters_IncludesParameterValues()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ID, Name", "Users", "ID = @UserId AND Status = @Status");
|
||||
query.Parameters["UserId"] = 123;
|
||||
query.Parameters["Status"] = "Active";
|
||||
_collection.Add(query);
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateQueryCompositionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Parameters Used"));
|
||||
Assert.That(report, Does.Contain("@UserId"));
|
||||
Assert.That(report, Does.Contain("@Status"));
|
||||
Assert.That(report, Does.Contain("123"));
|
||||
Assert.That(report, Does.Contain("Active"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithQueries_GeneratesFlowDiagram()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
_collection.Add(new QueryBreakdown("OrderID", "Orders"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(diagram, Does.Contain("```mermaid"));
|
||||
Assert.That(diagram, Does.Contain("flowchart TD"));
|
||||
Assert.That(diagram, Does.Contain("Batch Start"));
|
||||
Assert.That(diagram, Does.Contain("Query 0"));
|
||||
Assert.That(diagram, Does.Contain("Query 1"));
|
||||
Assert.That(diagram, Does.Contain("Batch Complete"));
|
||||
Assert.That(diagram, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithTransaction_IncludesTransactionStatements()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection, includeTransaction: true);
|
||||
|
||||
// Assert
|
||||
Assert.That(diagram, Does.Contain("BEGIN TRANSACTION"));
|
||||
Assert.That(diagram, Does.Contain("COMMIT TRANSACTION"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithQueries_ValidatesProperConnections()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
_collection.Add(new QueryBreakdown("OrderID", "Orders"));
|
||||
_collection.Add(new QueryBreakdown("ProductID", "Products"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection);
|
||||
|
||||
// Assert
|
||||
// Verify proper connections between nodes
|
||||
Assert.That(diagram, Does.Contain("Start([Batch Start]) --> node0")); // Start connects to first node
|
||||
Assert.That(diagram, Does.Contain("node0[\"Query 0\"] --> node1")); // Query 0 to Query 1
|
||||
Assert.That(diagram, Does.Contain("node1[\"Query 1\"] --> node2")); // Query 1 to Query 2
|
||||
Assert.That(diagram, Does.Contain("node2[\"Query 2\"] --> End")); // Last query connects to End
|
||||
// Verify no dangling nodes
|
||||
Assert.That(diagram, Does.Not.Contain("node3")); // No extra unconnected node
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateBatchFlowDiagram_WithTransaction_ValidatesProperConnections()
|
||||
{
|
||||
// Arrange
|
||||
_collection.Add(new QueryBreakdown("ID, Name", "Users"));
|
||||
_collection.Add(new QueryBreakdown("OrderID", "Orders"));
|
||||
|
||||
// Act
|
||||
var diagram = QueryBreakdownCollectionGenerator.GenerateBatchFlowDiagram(_collection, includeTransaction: true);
|
||||
|
||||
// Assert
|
||||
// Verify proper transaction flow
|
||||
Assert.That(diagram, Does.Contain("Start([Batch Start]) --> node0")); // Start connects to BEGIN TRANSACTION
|
||||
Assert.That(diagram, Does.Contain("node0[\"BEGIN TRANSACTION\"]")); // BEGIN TRANSACTION node
|
||||
Assert.That(diagram, Does.Contain("node0 --> node1")); // BEGIN to first query
|
||||
Assert.That(diagram, Does.Contain("node1[\"Query 0\"] --> node2")); // Query 0 to Query 1
|
||||
Assert.That(diagram, Does.Contain("node2[\"Query 1\"] --> node3")); // Query 1 to COMMIT
|
||||
Assert.That(diagram, Does.Contain("node3[\"COMMIT TRANSACTION\"]")); // COMMIT node
|
||||
Assert.That(diagram, Does.Contain("node3 --> End")); // COMMIT to End
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_EmptyCollection_GeneratesValidMarkdown()
|
||||
{
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("Collection Summary"));
|
||||
Assert.That(report, Does.Contain("Total Queries"));
|
||||
Assert.That(report, Does.Contain("0"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateCollectionReport_MultipleQueries_ContainsAllSections()
|
||||
{
|
||||
// Arrange
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
_collection.Add(new QueryBreakdown($"Col{i}", $"Table{i}"));
|
||||
}
|
||||
|
||||
// Act
|
||||
var report = QueryBreakdownCollectionGenerator.GenerateCollectionReport(_collection);
|
||||
|
||||
// Assert
|
||||
Assert.That(report, Does.Contain("## Collection Summary"));
|
||||
Assert.That(report, Does.Contain("## Parameter Analysis"));
|
||||
Assert.That(report, Does.Contain("## Query Composition Report"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
using Strata.SqlTools.Breakdowns.SqlServer;
|
||||
using Strata.SqlTools.Markdown.SqlServer;
|
||||
using Interfaces = Strata.SqlTools.SqlBreakdown.Interfaces;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.SqlServer;
|
||||
|
||||
[TestFixture]
|
||||
public class QueryBreakdownGeneratorTests
|
||||
{
|
||||
private QueryBreakdownGenerator _generator = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_generator = new QueryBreakdownGenerator();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithSimpleQuery_GeneratesFlowchart()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("ID, Name", "Users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithComplexQuery_IncludesAllClauses()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown(
|
||||
"u.ID, u.Name, COUNT(o.OrderID) as OrderCount",
|
||||
"Users u JOIN Orders o ON u.ID = o.UserID",
|
||||
"u.Active = 1"
|
||||
);
|
||||
query.GroupByClause.Clause = "u.ID, u.Name";
|
||||
query.HavingClause.Clause = "COUNT(o.OrderID) > 5";
|
||||
query.OrderByClause.Clause = "OrderCount DESC";
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "User Orders Query");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("### User Orders Query"));
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result, Does.Contain("FROM"));
|
||||
Assert.That(result, Does.Contain("WHERE"));
|
||||
Assert.That(result, Does.Contain("GROUP BY"));
|
||||
Assert.That(result, Does.Contain("HAVING"));
|
||||
Assert.That(result, Does.Contain("ORDER BY"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithWhereClause_UsesDecisionShape()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("*", "Products", "Price > 100");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("WHERE"));
|
||||
Assert.That(result, Does.Contain("{"));
|
||||
Assert.That(result, Does.Contain("}"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_ParsedQuery_GeneratesDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var sql = @"
|
||||
SELECT u.ID, u.Name, u.Email
|
||||
FROM Users u
|
||||
WHERE u.Active = 1
|
||||
ORDER BY u.Name";
|
||||
|
||||
var query = QueryBreakdown.Parse(sql);
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Does.Contain("mermaid"));
|
||||
Assert.That(result, Does.Contain("SELECT"));
|
||||
Assert.That(result.Length, Is.GreaterThan(100));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithTitle_IncludesTitle()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("*", "Users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query, "Test Query");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("### Test Query"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithoutTitle_NoTitle()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("*", "Users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Not.StartWith("###"));
|
||||
Assert.That(result, Does.StartWith("```mermaid"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_WithLongClause_TruncatesText()
|
||||
{
|
||||
// Arrange
|
||||
var longSelect = string.Join(", ", Enumerable.Range(1, 50).Select(i => $"Column{i}"));
|
||||
var query = new QueryBreakdown(longSelect, "LargeTable");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("..."));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMermaidDiagram_ISqlBreakdown_GeneratesSimpleDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("*", "Users");
|
||||
query.SetupClauses.Add("CREATE TEMP TABLE #Temp (ID INT)");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateMermaidDiagram((Interfaces.ISqlBreakdown)query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("mermaid"));
|
||||
Assert.That(result, Does.Contain("flowchart TD"));
|
||||
Assert.That(result, Does.Contain("Users"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
using Strata.SqlTools.Breakdowns.SqlServer;
|
||||
using Strata.SqlTools.Markdown.SqlServer;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.SqlServer;
|
||||
|
||||
[TestFixture]
|
||||
[Ignore("These tests are designed to generate markdown files from SQL queries in the Queries directory. They are not meant to be run as part of regular unit testing, but can be executed manually when needed.")]
|
||||
[Category("MarkdownGeneration")]
|
||||
public class QueryMarkdownGenerationTests
|
||||
{
|
||||
private QueryBreakdownGenerator _generator = null!;
|
||||
private string _queriesSourcePath = null!;
|
||||
private string _markdownOutputPath = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_generator = new QueryBreakdownGenerator();
|
||||
|
||||
// Get the solution root directory
|
||||
var testDirectory = TestContext.CurrentContext.TestDirectory;
|
||||
var solutionRoot = Directory.GetParent(testDirectory)?.Parent?.Parent?.Parent?.Parent?.FullName;
|
||||
|
||||
if (solutionRoot == null)
|
||||
throw new InvalidOperationException("Could not determine solution root directory");
|
||||
|
||||
_queriesSourcePath = Path.Combine(solutionRoot, "Queries");
|
||||
_markdownOutputPath = Path.Combine(solutionRoot, "docs", "queries");
|
||||
|
||||
// Ensure output directory exists
|
||||
if (!Directory.Exists(_markdownOutputPath))
|
||||
{
|
||||
Directory.CreateDirectory(_markdownOutputPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMarkdownForAllQueries_CreatesMarkdownFiles()
|
||||
{
|
||||
// Arrange
|
||||
Assert.That(Directory.Exists(_queriesSourcePath), Is.True,
|
||||
$"Queries directory not found at: {_queriesSourcePath}");
|
||||
|
||||
var sqlFiles = Directory.GetFiles(_queriesSourcePath, "*.sql");
|
||||
Assert.That(sqlFiles, Is.Not.Empty, "No SQL files found in Queries directory");
|
||||
|
||||
int successCount = 0;
|
||||
int skippedCount = 0;
|
||||
|
||||
// Act & Assert for each file
|
||||
foreach (var sqlFile in sqlFiles)
|
||||
{
|
||||
var fileName = Path.GetFileNameWithoutExtension(sqlFile);
|
||||
var sqlContent = File.ReadAllText(sqlFile);
|
||||
|
||||
try
|
||||
{
|
||||
// Parse the SQL query
|
||||
var queryBreakdown = QueryBreakdown.Parse(sqlContent);
|
||||
|
||||
// Generate markdown with the filename as title
|
||||
var markdown = _generator.GenerateMermaidDiagram(queryBreakdown, fileName);
|
||||
|
||||
// Verify markdown was generated
|
||||
Assert.That(markdown, Is.Not.Null);
|
||||
Assert.That(markdown, Does.Contain("```mermaid"));
|
||||
Assert.That(markdown, Does.Contain(fileName));
|
||||
|
||||
// Write to output file
|
||||
var outputFile = Path.Combine(_markdownOutputPath, $"{fileName}.md");
|
||||
File.WriteAllText(outputFile, markdown);
|
||||
|
||||
// Verify file was created
|
||||
Assert.That(File.Exists(outputFile), Is.True,
|
||||
$"Markdown file was not created: {outputFile}");
|
||||
|
||||
TestContext.WriteLine($"Generated: {fileName}.md");
|
||||
successCount++;
|
||||
}
|
||||
catch (FormatException ex)
|
||||
{
|
||||
// Skip files that can't be parsed (e.g., partial queries with only WITH clauses)
|
||||
TestContext.WriteLine($"Skipped: {fileName}.sql - {ex.Message}");
|
||||
skippedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
TestContext.WriteLine($"Generated {successCount} markdown files, skipped {skippedCount} files in {_markdownOutputPath}");
|
||||
Assert.That(successCount, Is.GreaterThan(0), "At least one markdown file should be generated");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateMarkdownForAllQueries_IncludesQuerySource()
|
||||
{
|
||||
// Arrange
|
||||
var sqlFiles = Directory.GetFiles(_queriesSourcePath, "*.sql");
|
||||
Assert.That(sqlFiles, Is.Not.Empty);
|
||||
|
||||
int successCount = 0;
|
||||
|
||||
// Act & Assert
|
||||
foreach (var sqlFile in sqlFiles)
|
||||
{
|
||||
var fileName = Path.GetFileNameWithoutExtension(sqlFile);
|
||||
var sqlContent = File.ReadAllText(sqlFile);
|
||||
|
||||
try
|
||||
{
|
||||
var queryBreakdown = QueryBreakdown.Parse(sqlContent);
|
||||
var markdown = _generator.GenerateMermaidDiagram(queryBreakdown, fileName);
|
||||
|
||||
// Add source SQL to the markdown
|
||||
var fullMarkdown = $"{markdown}\n\n## Source SQL\n\n```sql\n{sqlContent}\n```\n";
|
||||
|
||||
var outputFile = Path.Combine(_markdownOutputPath, $"{fileName}.md");
|
||||
File.WriteAllText(outputFile, fullMarkdown);
|
||||
|
||||
// Verify the output includes both diagram and source
|
||||
var writtenContent = File.ReadAllText(outputFile);
|
||||
Assert.That(writtenContent, Does.Contain("```mermaid"));
|
||||
Assert.That(writtenContent, Does.Contain("## Source SQL"));
|
||||
Assert.That(writtenContent, Does.Contain(sqlContent));
|
||||
|
||||
successCount++;
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
// Skip files that can't be parsed
|
||||
TestContext.WriteLine($"Skipped: {fileName}.sql (could not parse)");
|
||||
}
|
||||
}
|
||||
|
||||
Assert.That(successCount, Is.GreaterThan(0), "At least one markdown file should be generated");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AllQueriesDirectory_Exists()
|
||||
{
|
||||
// Verify the Queries directory exists
|
||||
Assert.That(Directory.Exists(_queriesSourcePath), Is.True,
|
||||
$"Queries directory should exist at: {_queriesSourcePath}");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OutputDirectory_IsCreated()
|
||||
{
|
||||
// Verify the output directory was created
|
||||
Assert.That(Directory.Exists(_markdownOutputPath), Is.True,
|
||||
$"Output directory should exist at: {_markdownOutputPath}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
using Strata.SqlTools.Breakdowns.SqlServer;
|
||||
using Strata.SqlTools.Markdown.SqlServer;
|
||||
|
||||
namespace Strata.SqlTools.Markdown.Tests.SqlServer;
|
||||
|
||||
[TestFixture]
|
||||
public class SqlStatementGeneratorTests
|
||||
{
|
||||
private SqlStatementGenerator _generator = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_generator = new SqlStatementGenerator();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_WithSimpleQuery_GeneratesSequence()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("*", "Users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("sequenceDiagram"));
|
||||
Assert.That(result, Does.Contain("App->>DB"));
|
||||
Assert.That(result, Does.Contain("DB-->>App"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_WithSetupClauses_IncludesSetup()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("*", "Users");
|
||||
query.SetupClauses.Add("CREATE TEMP TABLE #Temp (ID INT)");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("Setup Clauses"));
|
||||
Assert.That(result, Does.Contain("activate DB"));
|
||||
Assert.That(result, Does.Contain("deactivate DB"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_WithFinishClauses_IncludesFinish()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("*", "Users");
|
||||
query.FinishClauses.Add("DROP TABLE #Temp");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("Finish Clauses"));
|
||||
Assert.That(result, Does.Contain("Cleanup"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSequenceDiagram_WithTitle_IncludesTitle()
|
||||
{
|
||||
// Arrange
|
||||
var query = new QueryBreakdown("*", "Users");
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateSequenceDiagram(query, "Query Execution");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("### Query Execution"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateEntityRelationshipDiagram_WithTables_GeneratesERDiagram()
|
||||
{
|
||||
// Arrange
|
||||
var tables = new[] { "Users", "Orders", "Products" };
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateEntityRelationshipDiagram(tables);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("```mermaid"));
|
||||
Assert.That(result, Does.Contain("erDiagram"));
|
||||
Assert.That(result, Does.Contain("Users"));
|
||||
Assert.That(result, Does.Contain("Orders"));
|
||||
Assert.That(result, Does.Contain("Products"));
|
||||
Assert.That(result, Does.Contain("```"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateEntityRelationshipDiagram_WithTitle_IncludesTitle()
|
||||
{
|
||||
// Arrange
|
||||
var tables = new[] { "Users", "Orders" };
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateEntityRelationshipDiagram(tables, "Database Schema");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("### Database Schema"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateEntityRelationshipDiagram_CleansTableNames()
|
||||
{
|
||||
// Arrange
|
||||
var tables = new[] { "[dbo].[Users]", "schema.Orders" };
|
||||
|
||||
// Act
|
||||
var result = _generator.GenerateEntityRelationshipDiagram(tables);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("dbo_Users"));
|
||||
Assert.That(result, Does.Contain("schema_Orders"));
|
||||
Assert.That(result, Does.Not.Contain("["));
|
||||
Assert.That(result, Does.Not.Contain("]"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="NUnit" Version="4.2.2" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.3.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Strata.SqlTools.SqlBreakdown\Strata.SqlTools.SqlBreakdown.csproj" />
|
||||
<ProjectReference Include="..\..\src\Strata.SqlTools.SqlServer\Strata.SqlTools.SqlServer.csproj" />
|
||||
<ProjectReference Include="..\..\src\Strata.SqlTools.Snowflake\Strata.SqlTools.Snowflake.csproj" />
|
||||
<ProjectReference Include="..\..\src\Strata.SqlTools.PostgreSql\Strata.SqlTools.PostgreSql.csproj" />
|
||||
<ProjectReference Include="..\..\src\Strata.SqlTools.LinqToSql\Strata.SqlTools.LinqToSql.csproj" />
|
||||
<ProjectReference Include="..\..\src\Strata.SqlTools.Markdown\Strata.SqlTools.Markdown.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="NUnit.Framework" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1 @@
|
||||
global using NUnit.Framework;
|
||||
Reference in New Issue
Block a user