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