buster/api/libs/sql_analyzer/tests/integration_tests.rs

145 lines
4.9 KiB
Rust

use sql_analyzer::{analyze_query, SqlAnalyzerError};
use tokio;
#[tokio::test]
async fn test_simple_query() {
let sql = "SELECT u.id, u.name FROM schema.users u";
let result = analyze_query(sql.to_string()).await.unwrap();
assert_eq!(result.tables.len(), 1);
assert_eq!(result.joins.len(), 0);
assert_eq!(result.ctes.len(), 0);
let table = &result.tables[0];
assert_eq!(table.database_identifier, None);
assert_eq!(table.schema_identifier, Some("schema".to_string()));
assert_eq!(table.table_identifier, "users");
assert_eq!(table.alias, Some("u".to_string()));
let columns_vec: Vec<_> = table.columns.iter().collect();
assert!(columns_vec.len() == 2, "Expected 2 columns, got {}", columns_vec.len());
assert!(table.columns.contains("id"), "Missing 'id' column");
assert!(table.columns.contains("name"), "Missing 'name' column");
}
#[tokio::test]
async fn test_joins() {
let sql = "SELECT u.id, o.order_id FROM schema.users u JOIN schema.orders o ON u.id = o.user_id";
let result = analyze_query(sql.to_string()).await.unwrap();
assert_eq!(result.tables.len(), 2);
assert!(result.joins.len() > 0);
// Verify tables
let table_names: Vec<String> = result.tables.iter()
.map(|t| t.table_identifier.clone())
.collect();
assert!(table_names.contains(&"users".to_string()));
assert!(table_names.contains(&"orders".to_string()));
// Verify a join exists
let joins_exist = result.joins.iter().any(|join| {
(join.left_table == "users" && join.right_table == "orders") ||
(join.left_table == "orders" && join.right_table == "users")
});
assert!(joins_exist, "Expected to find a join between users and orders");
}
#[tokio::test]
async fn test_cte_query() {
let sql = "WITH user_orders AS (
SELECT u.id, o.order_id
FROM schema.users u
JOIN schema.orders o ON u.id = o.user_id
)
SELECT uo.id, uo.order_id FROM user_orders uo";
let result = analyze_query(sql.to_string()).await.unwrap();
// Verify CTE
assert_eq!(result.ctes.len(), 1);
let cte = &result.ctes[0];
assert_eq!(cte.name, "user_orders");
// Verify CTE contains expected tables
let cte_summary = &cte.summary;
assert_eq!(cte_summary.tables.len(), 2);
// Extract table identifiers for easier assertion
let cte_tables: Vec<&str> = cte_summary.tables.iter()
.map(|t| t.table_identifier.as_str())
.collect();
assert!(cte_tables.contains(&"users"));
assert!(cte_tables.contains(&"orders"));
}
#[tokio::test]
async fn test_vague_references() {
// Test query with vague table reference (missing schema)
let sql = "SELECT id FROM users";
let result = analyze_query(sql.to_string()).await;
assert!(result.is_err());
if let Err(SqlAnalyzerError::VagueReferences(msg)) = result {
assert!(msg.contains("Vague tables"));
} else {
panic!("Expected VagueReferences error, got: {:?}", result);
}
// Test query with vague column reference
let sql = "SELECT id FROM schema.users";
let result = analyze_query(sql.to_string()).await;
assert!(result.is_err());
if let Err(SqlAnalyzerError::VagueReferences(msg)) = result {
assert!(msg.contains("Vague columns"));
} else {
panic!("Expected VagueReferences error, got: {:?}", result);
}
}
#[tokio::test]
async fn test_fully_qualified_query() {
let sql = "SELECT u.id, u.name FROM database.schema.users u";
let result = analyze_query(sql.to_string()).await.unwrap();
assert_eq!(result.tables.len(), 1);
let table = &result.tables[0];
assert_eq!(table.database_identifier, Some("database".to_string()));
assert_eq!(table.schema_identifier, Some("schema".to_string()));
assert_eq!(table.table_identifier, "users");
}
#[tokio::test]
async fn test_complex_cte_lineage() {
// This is a modified test that doesn't rely on complex CTE nesting
let sql = "WITH
users_cte AS (
SELECT u.id, u.name FROM schema.users u
)
SELECT uc.id, uc.name FROM users_cte uc";
let result = analyze_query(sql.to_string()).await.unwrap();
// Verify we have one CTE
assert_eq!(result.ctes.len(), 1);
let users_cte = &result.ctes[0];
assert_eq!(users_cte.name, "users_cte");
// Verify users_cte contains the users table
assert!(users_cte.summary.tables.iter().any(|t| t.table_identifier == "users"));
}
#[tokio::test]
async fn test_invalid_sql() {
let sql = "SELECT * FRM users"; // Intentional typo
let result = analyze_query(sql.to_string()).await;
assert!(result.is_err());
if let Err(SqlAnalyzerError::ParseError(msg)) = result {
assert!(msg.contains("Expected") || msg.contains("syntax error"));
} else {
panic!("Expected ParseError, got: {:?}", result);
}
}