analysis test and generate command

This commit is contained in:
dal 2025-05-13 10:10:43 -06:00
parent d76485e586
commit 5aed7bcc7c
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
2 changed files with 97 additions and 1 deletions

View File

@ -2230,4 +2230,50 @@ async fn test_bigquery_count_with_interval() {
assert!(table.columns.contains("message_id"), "Missing 'message_id' column");
assert!(table.columns.contains("created_at"), "Missing 'created_at' column");
}
}
#[tokio::test]
async fn test_postgres_cte_with_date_trunc() {
let sql = r#"
WITH recent_data AS (
SELECT
tsr.year AS sales_year,
tsr.month AS sales_month,
tsr.metric_totalsalesrevenue AS total_revenue
FROM postgres.ont_ont.total_sales_revenue tsr
WHERE cast(concat(tsr.year, '-', tsr.month, '-01') AS date)
>= date_trunc('month', CURRENT_DATE) - INTERVAL '5 months'
)
SELECT
DATE_TRUNC('month', cast(concat(sales_year, '-', sales_month, '-01') AS date)) AS month_start,
COALESCE(total_revenue, 0) AS total_revenue
FROM recent_data
ORDER BY month_start ASC;
"#;
let result = analyze_query(sql.to_string(), "postgres").await.unwrap();
// Check CTE detection
assert_eq!(result.ctes.len(), 1, "Should detect one CTE");
let cte = &result.ctes[0];
assert_eq!(cte.name, "recent_data", "CTE should be named 'recent_data'");
// Check base table detection
assert_eq!(result.tables.len(), 1, "Should detect one base table");
let table = &result.tables[0];
assert_eq!(table.database_identifier, Some("postgres".to_string()));
assert_eq!(table.schema_identifier, Some("ont_ont".to_string()));
assert_eq!(table.table_identifier, "total_sales_revenue");
// Check columns in base table
assert!(table.columns.contains("year"), "Missing 'year' column");
assert!(table.columns.contains("month"), "Missing 'month' column");
assert!(table.columns.contains("metric_totalsalesrevenue"), "Missing 'metric_totalsalesrevenue' column");
// Check CTE columns
let cte_table = &cte.summary.tables[0];
assert!(cte_table.columns.contains("sales_year"), "Missing 'sales_year' in CTE");
assert!(cte_table.columns.contains("sales_month"), "Missing 'sales_month' in CTE");
assert!(cte_table.columns.contains("total_revenue"), "Missing 'total_revenue' in CTE");
}

View File

@ -453,6 +453,56 @@ for (unique_id, node) in &dbt_catalog.nodes {
match existing_yaml_model_opt {
Some(mut existing_model) => {
// --- Reconciliation Logic for Existing Model ---
let mut model_updated = false;
let original_dim_count = existing_model.dimensions.len();
let original_measure_count = existing_model.measures.len();
// Get the set of column names from the dbt catalog for this model
let catalog_column_names: HashSet<String> = catalog_node.columns
.keys()
.cloned()
.collect();
// Remove dimensions that are no longer in the catalog
existing_model.dimensions.retain(|dim| {
let keep = catalog_column_names.contains(&dim.name);
if !keep {
columns_removed_count += 1;
model_updated = true;
println!(" - Removing dimension '{}' (not in catalog)", dim.name.yellow());
}
keep
});
// Remove measures that are no longer in the catalog
existing_model.measures.retain(|measure| {
let keep = catalog_column_names.contains(&measure.name);
if !keep {
columns_removed_count += 1;
model_updated = true;
println!(" - Removing measure '{}' (not in catalog)", measure.name.yellow());
}
keep
});
// Note: We do NOT remove metrics, filters, or relationships automatically
// as they might represent derived logic or explicitly defined connections
// not directly tied 1:1 with current physical columns.
// TODO: Add logic here to ADD new columns from the catalog as dimensions/measures
// if they don't already exist in the existing_model.
if model_updated {
let yaml_string = serde_yaml::to_string(&existing_model)?;
fs::write(&individual_semantic_yaml_path, yaml_string)?;
models_updated_count += 1;
println!(" {} Updated existing semantic model: {}", "🔄".cyan(), individual_semantic_yaml_path.display().to_string().cyan());
} else {
// If no columns were removed, maybe check if columns need *adding* later?
// For now, just indicate no changes needed based on removal.
// println!(" {} No column removals needed for: {}", "✅".dimmed(), individual_semantic_yaml_path.display().to_string().dimmed());
}
}
None => { // New semantic model
let mut dimensions = Vec::new();