chore: initial git load of code space
This commit is contained in:
+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"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user