dbmcp_postgres/tools/
list_databases.rs1use dbmcp_server::pagination::Pager;
4use dbmcp_server::types::{ListDatabasesRequest, ListDatabasesResponse};
5
6use super::prelude::*;
7
8const NAME: &str = "listDatabases";
9const TITLE: &str = "List Databases";
10const DESCRIPTION: &str = include_str!("../../assets/tools/list_databases/default.md");
11
12pub(crate) struct ListDatabasesTool;
14
15impl ToolBase for ListDatabasesTool {
16 type Parameter = ListDatabasesRequest;
17 type Output = ListDatabasesResponse;
18 type Error = ErrorData;
19
20 fn name() -> Cow<'static, str> {
21 NAME.into()
22 }
23
24 fn title() -> Option<String> {
25 Some(TITLE.into())
26 }
27
28 fn description() -> Option<Cow<'static, str>> {
29 Some(DESCRIPTION.into())
30 }
31
32 fn annotations() -> Option<ToolAnnotations> {
33 Some(
34 ToolAnnotations::new()
35 .read_only(true)
36 .destructive(false)
37 .idempotent(true)
38 .open_world(false),
39 )
40 }
41
42 fn input_schema() -> Option<Arc<JsonObject>> {
43 Some(input_schema::<Self::Parameter>(false))
44 }
45
46 fn output_schema() -> Option<Arc<JsonObject>> {
47 Some(output_schema::<Self::Output>())
48 }
49}
50
51impl AsyncTool<PostgresHandler> for ListDatabasesTool {
52 async fn invoke(handler: &PostgresHandler, params: Self::Parameter) -> Result<Self::Output, Self::Error> {
53 handler.list_databases(params).await
54 }
55}
56
57impl PostgresHandler {
58 pub async fn list_databases(
69 &self,
70 ListDatabasesRequest { cursor }: ListDatabasesRequest,
71 ) -> Result<ListDatabasesResponse, ErrorData> {
72 let pager = Pager::new(cursor, self.config.page_size);
73 let query = format!(
74 r"
75 SELECT datname
76 FROM pg_database
77 WHERE datistemplate = false
78 ORDER BY datname
79 LIMIT {} OFFSET {}",
80 pager.limit(),
81 pager.offset(),
82 );
83
84 let rows: Vec<String> = self.connection.fetch_scalar(query.as_str(), None).await?;
85 let (databases, next_cursor) = pager.paginate(rows);
86
87 Ok(ListDatabasesResponse { databases, next_cursor })
88 }
89}