fraiseql_cli/commands/cost.rs
1//! Cost command - lightweight complexity scoring for queries
2//!
3//! Usage: fraiseql cost `<query>` `[--json]`
4
5use anyhow::Result;
6use fraiseql_core::graphql::{complexity::RequestValidator, parse_query};
7use serde::Serialize;
8
9use crate::output::CommandResult;
10
11/// Response with cost estimation
12#[derive(Debug, Serialize)]
13pub struct CostResponse {
14 /// The GraphQL query being analyzed
15 pub query: String,
16 /// Complexity score based on query depth and breadth (pagination-aware)
17 pub complexity_score: usize,
18 /// Estimated execution cost
19 pub estimated_cost: usize,
20 /// Maximum query depth
21 pub depth: usize,
22 /// Number of aliased fields
23 pub alias_count: usize,
24}
25
26/// Run cost command (minimal complexity analysis)
27///
28/// # Errors
29///
30/// Returns an error if the query cannot be parsed or if complexity analysis
31/// fails. Also propagates errors from JSON serialization of the response.
32pub fn run(query: &str) -> Result<CommandResult> {
33 // Validate query syntax
34 let _parsed = parse_query(query)?;
35
36 // AST-based complexity analysis
37 let validator = RequestValidator::default();
38 let metrics = validator.analyze(query)?;
39
40 let response = CostResponse {
41 query: query.to_string(),
42 complexity_score: metrics.complexity,
43 estimated_cost: metrics.depth * 25, // Rough cost estimation
44 depth: metrics.depth,
45 alias_count: metrics.alias_count,
46 };
47
48 Ok(CommandResult::success("cost", serde_json::to_value(&response)?))
49}