dbmcp_sqlite/types.rs
1//! SQLite-specific MCP tool request types.
2//!
3//! Unlike `MySQL` and `PostgreSQL`, `SQLite` operates on a single file and
4//! has no database selection, so these types omit the `database` field
5//! present in the shared server types. `ListEntries` and
6//! `ListEntriesResponse` live in the shared `dbmcp-server` crate; they are
7//! re-exported here so call sites can keep importing them from
8//! `crate::types`.
9
10use dbmcp_server::pagination::Cursor;
11use schemars::JsonSchema;
12use serde::Deserialize;
13
14pub use dbmcp_server::types::{ListEntries, ListEntriesResponse};
15
16/// Request for the `dropTable` tool.
17#[derive(Debug, Default, Deserialize, JsonSchema)]
18pub struct DropTableRequest {
19 /// Name of the table to drop. Must be non-empty.
20 pub table: String,
21}
22
23/// Request for the `SQLite` `listTables` tool — supports optional search filter and detailed mode.
24#[derive(Debug, Default, Deserialize, JsonSchema)]
25pub struct ListTablesRequest {
26 /// Opaque pagination cursor. Omit (or pass `null`) for the first page.
27 /// On subsequent calls, pass the `nextCursor` returned by the previous
28 /// response verbatim. Cursors are opaque — do not parse, modify, or persist.
29 #[serde(default)]
30 pub cursor: Option<Cursor>,
31 /// Optional case-insensitive filter on table names. The input is used within a `LIKE`
32 /// clause: `%` matches any sequence of characters and `_` matches any single character.
33 #[serde(default)]
34 pub search: Option<String>,
35 /// When `true`, each returned entry is a full metadata object (columns,
36 /// constraints, indexes, triggers); when `false` or omitted, each entry
37 /// is the bare table-name string.
38 #[serde(default)]
39 pub detailed: bool,
40}
41
42/// Request for the `listViews` tool.
43#[derive(Debug, Default, Deserialize, JsonSchema)]
44pub struct ListViewsRequest {
45 /// Opaque pagination cursor. Omit (or pass `null`) for the first page.
46 /// On subsequent calls, pass the `nextCursor` returned by the previous
47 /// response verbatim. Cursors are opaque — do not parse, modify, or persist.
48 #[serde(default)]
49 pub cursor: Option<Cursor>,
50}
51
52/// Request for the `SQLite` `listTriggers` tool — supports optional search filter and detailed mode.
53#[derive(Debug, Default, Deserialize, JsonSchema)]
54pub struct ListTriggersRequest {
55 /// Opaque pagination cursor. Omit (or pass `null`) for the first page.
56 /// On subsequent calls, pass the `nextCursor` returned by the previous
57 /// response verbatim. Cursors are opaque — do not parse, modify, or persist.
58 #[serde(default)]
59 pub cursor: Option<Cursor>,
60 /// Optional case-insensitive filter on trigger names. The input is used within a `LIKE`
61 /// clause: `%` matches any sequence of characters and `_` matches any single character.
62 #[serde(default)]
63 pub search: Option<String>,
64 /// When `true`, each returned entry is a full metadata object (schema,
65 /// table, definition); when `false` or omitted, each entry is the bare
66 /// trigger-name string.
67 #[serde(default)]
68 pub detailed: bool,
69}
70
71/// Request for the `writeQuery` tool.
72#[derive(Debug, Default, Deserialize, JsonSchema)]
73pub struct QueryRequest {
74 /// The SQL query to execute.
75 pub query: String,
76}
77
78/// Request for the `readQuery` tool.
79#[derive(Debug, Default, Deserialize, JsonSchema)]
80pub struct ReadQueryRequest {
81 /// The SQL query to execute.
82 pub query: String,
83 /// Opaque pagination cursor. Omit (or pass `null`) for the first page.
84 /// On subsequent calls, pass the `nextCursor` returned by the previous
85 /// response verbatim. Cursors are opaque — do not parse, modify, or persist.
86 /// Ignored for `EXPLAIN` statements.
87 #[serde(default)]
88 pub cursor: Option<Cursor>,
89}
90
91/// Request for the `explainQuery` tool.
92#[derive(Debug, Default, Deserialize, JsonSchema)]
93pub struct ExplainQueryRequest {
94 /// The SQL query to explain.
95 pub query: String,
96}
97
98#[cfg(test)]
99mod tests {
100 use super::{ListTablesRequest, ListTriggersRequest};
101
102 #[test]
103 fn list_tables_request_defaults_to_brief_mode_without_search() {
104 let req: ListTablesRequest = serde_json::from_str("{}").expect("empty object should parse");
105 assert!(req.search.is_none());
106 assert!(!req.detailed, "detailed must default to false");
107 }
108
109 #[test]
110 fn list_tables_request_accepts_search_and_detailed() {
111 let req: ListTablesRequest = serde_json::from_str(r#"{"search": "post", "detailed": true}"#).expect("parse");
112 assert_eq!(req.search.as_deref(), Some("post"));
113 assert!(req.detailed);
114 }
115
116 #[test]
117 fn list_triggers_request_defaults_to_brief_mode_without_search() {
118 let req: ListTriggersRequest = serde_json::from_str("{}").expect("empty object should parse");
119 assert!(req.search.is_none());
120 assert!(!req.detailed, "detailed must default to false");
121 }
122
123 #[test]
124 fn list_triggers_request_accepts_search_and_detailed() {
125 let req: ListTriggersRequest = serde_json::from_str(r#"{"search": "audit", "detailed": true}"#).expect("parse");
126 assert_eq!(req.search.as_deref(), Some("audit"));
127 assert!(req.detailed);
128 }
129}