dbmcp_sqlite/tools/
explain_query.rs1use dbmcp_pii::MaybeRedact as _;
4use dbmcp_server::types::QueryResponse;
5use dbmcp_sql::validation::validate_single_statement;
6
7use super::prelude::*;
8use crate::types::ExplainQueryRequest;
9
10const NAME: &str = "explainQuery";
11const TITLE: &str = "Explain Query";
12const DESCRIPTION: &str = include_str!("../../assets/tools/explain_query.md");
13
14pub(crate) struct ExplainQueryTool;
16
17impl ToolBase for ExplainQueryTool {
18 type Parameter = ExplainQueryRequest;
19 type Output = QueryResponse;
20 type Error = ErrorData;
21
22 fn name() -> Cow<'static, str> {
23 NAME.into()
24 }
25
26 fn title() -> Option<String> {
27 Some(TITLE.into())
28 }
29
30 fn description() -> Option<Cow<'static, str>> {
31 Some(DESCRIPTION.into())
32 }
33
34 fn annotations() -> Option<ToolAnnotations> {
35 Some(
36 ToolAnnotations::new()
37 .read_only(true)
38 .destructive(false)
39 .idempotent(true)
40 .open_world(true),
41 )
42 }
43
44 fn input_schema() -> Option<Arc<JsonObject>> {
45 Some(input_schema::<Self::Parameter>(true))
46 }
47
48 fn output_schema() -> Option<Arc<JsonObject>> {
49 Some(output_schema::<Self::Output>())
50 }
51}
52
53impl AsyncTool<SqliteHandler> for ExplainQueryTool {
54 async fn invoke(handler: &SqliteHandler, params: Self::Parameter) -> Result<Self::Output, Self::Error> {
55 handler.explain_query(params).await
56 }
57}
58
59impl SqliteHandler {
60 pub async fn explain_query(
71 &self,
72 ExplainQueryRequest { query }: ExplainQueryRequest,
73 ) -> Result<QueryResponse, ErrorData> {
74 validate_single_statement(&query, &sqlparser::dialect::SQLiteDialect {})?;
75
76 let explain_sql = format!("EXPLAIN QUERY PLAN {query}");
77
78 let rows = self.connection.fetch_json(explain_sql.as_str(), None).await?;
79 let rows = self.redactor.redact_rows(rows).await?;
80
81 Ok(QueryResponse { rows })
82 }
83}