fraiseql-cli 2.0.0-rc.13

CLI tools for FraiseQL v2 - Schema compilation and development utilities
Documentation
//! Tests for cost command - shows query complexity scores only

use serde_json::json;

#[derive(Debug)]
struct CostResult {
    query:            String,
    complexity_score: usize,
    estimated_cost:   usize,
    depth:            usize,
    field_count:      usize,
}

fn calculate_cost(query: &str) -> anyhow::Result<CostResult> {
    // This would call the actual cost command
    // For testing, we use a simple calculation
    let depth = query.matches('{').count() / 2; // Rough estimate
    let field_count = query.split_whitespace().count();
    let score = depth * field_count.max(1);

    Ok(CostResult {
        query: query.to_string(),
        complexity_score: score,
        estimated_cost: depth * 50, // Rough cost estimate
        depth,
        field_count,
    })
}

#[test]
fn test_cost_simple_query() {
    let query = "query { users { id } }";
    let result = calculate_cost(query).unwrap();

    assert!(result.complexity_score > 0);
    assert!(result.estimated_cost > 0);
}

#[test]
fn test_cost_complex_query_higher_than_simple() {
    let simple = calculate_cost("query { users { id } }").unwrap();
    let complex = calculate_cost("query { users { posts { comments } } }").unwrap();

    assert!(complex.complexity_score > simple.complexity_score);
}

#[test]
fn test_cost_respects_field_count() {
    let few_fields = calculate_cost("query { users { id } }").unwrap();
    let many_fields = calculate_cost("query { users { id name email phone address } }").unwrap();

    // More fields should increase cost
    assert!(many_fields.complexity_score >= few_fields.complexity_score);
}

#[test]
fn test_cost_respects_depth() {
    let shallow = calculate_cost("query { users { id } }").unwrap();
    let deep =
        calculate_cost("query { users { posts { comments { author { name } } } } }").unwrap();

    // Deeper query should have higher cost
    assert!(deep.complexity_score > shallow.complexity_score);
}

#[test]
fn test_cost_result_is_deterministic() {
    let query = "query { users { id name } }";

    let result1 = calculate_cost(query).unwrap();
    let result2 = calculate_cost(query).unwrap();

    // Same query should give same cost
    assert_eq!(result1.complexity_score, result2.complexity_score);
}

#[test]
fn test_cost_result_serializes_to_json() {
    let query = "query { users { id } }";
    let result = calculate_cost(query).unwrap();

    let json_output = json!({
        "query": result.query,
        "complexity_score": result.complexity_score,
        "estimated_cost": result.estimated_cost,
        "depth": result.depth,
        "field_count": result.field_count,
    });

    assert_eq!(json_output["query"], query);
    assert!(json_output["complexity_score"].is_number());
}

#[test]
fn test_cost_is_faster_than_explain() {
    // Cost command should be minimal - just complexity analysis
    // No SQL generation, no execution planning
    let query = "query { users { id } }";

    let cost_result = calculate_cost(query).unwrap();

    // Should have only complexity info, not execution details
    assert!(cost_result.complexity_score > 0);
    assert_eq!(cost_result.query, query);
}

#[test]
fn test_cost_with_aliases() {
    // Test that cost accounts for aliased fields
    let query = "query { users: allUsers { id name } }";
    let result = calculate_cost(query).unwrap();

    assert!(result.complexity_score > 0);
}

#[test]
fn test_cost_with_directives() {
    // Cost should account for directives
    let query = "query { users { id @include(if: true) } }";
    let result = calculate_cost(query).unwrap();

    assert!(result.complexity_score > 0);
}

#[test]
fn test_cost_zero_for_empty_query() {
    let query = "query { }";
    let result = calculate_cost(query).unwrap();

    // Empty query should have minimal cost
    assert_eq!(result.complexity_score, 0);
}