Skip to main content

elicit_sqlx/
args.rs

1//! `ToSqlxArgs` — bridge trait for converting any [`Elicitation`] type into
2//! positional SQL arguments.
3//!
4//! # How it works
5//!
6//! Any type `T` that derives [`Elicitation`] (which implies `Serialize +
7//! DeserializeOwned + JsonSchema`) automatically implements [`ToSqlxArgs`] via
8//! a blanket impl.  The impl serializes `T` to JSON and extracts the field
9//! values in declaration order as a flat `Vec<serde_json::Value>`.
10//!
11//! The resulting vector can be passed directly as `args` to any driver plugin
12//! tool that accepts positional parameters:
13//!
14//! ```text
15//! my_type__to_sqlx_args { target: { name: "Alice", age: 30 } }
16//!     → { result: ["Alice", 30] }
17//!
18//! pg__execute { pool_id: "…", sql: "INSERT INTO users(name,age) VALUES($1,$2)",
19//!               args: ["Alice", 30] }
20//!     → { rows_affected: 1 }
21//! ```
22//!
23//! # Field ordering
24//!
25//! Fields are emitted in the order they appear in the JSON serialization of
26//! `T`.  For types that derive `serde::Serialize`, this matches the struct
27//! declaration order.  Renamed or skipped fields follow serde attribute rules.
28//!
29//! For non-object JSON values (e.g. a newtype wrapping a single scalar),
30//! the scalar itself is wrapped in a single-element `Vec`.
31//!
32//! # Factory usage
33//!
34//! Register a user type at server startup to get a typed binding tool:
35//!
36//! ```rust,ignore
37//! prime_to_sqlx_args::<CreateUser>();
38//! registry.register_type::<CreateUser>("create_user");
39//! // Agent can now call: create_user__to_sqlx_args { target: { … } }
40//! ```
41
42use elicitation_macros::reflect_trait;
43use serde::Serialize;
44
45/// Convert `self` into a flat list of positional SQL argument values.
46///
47/// Implemented automatically for all types that derive [`Elicitation`].
48/// The return value is suitable for direct use as the `args` field in
49/// `*__execute`, `*__fetch_all`, `*__fetch_one`, and `*__fetch_optional`
50/// driver tools.
51pub trait ToSqlxArgs {
52    /// Serialize `self` into ordered positional SQL argument values.
53    fn to_sqlx_args(&self) -> Vec<serde_json::Value>;
54}
55
56impl<T> ToSqlxArgs for T
57where
58    T: elicitation::Elicitation + Serialize,
59{
60    fn to_sqlx_args(&self) -> Vec<serde_json::Value> {
61        match serde_json::to_value(self).unwrap_or(serde_json::Value::Null) {
62            serde_json::Value::Object(map) => map.into_values().collect(),
63            other => vec![other],
64        }
65    }
66}
67
68/// Expose [`ToSqlxArgs`] as an agent-callable MCP tool factory.
69///
70/// For each registered type `T`, contributes one tool:
71/// - `{prefix}__to_sqlx_args` — convert a `T` value into positional SQL args
72///
73/// The `target` parameter must be the JSON representation of the `T` value.
74/// The output `Vec<serde_json::Value>` can be passed directly as `args` to
75/// any driver plugin execute or fetch tool.
76#[reflect_trait(crate::ToSqlxArgs)]
77pub trait ToSqlxArgsTools {
78    /// Serialize this value to a list of positional SQL argument values.
79    fn to_sqlx_args(&self) -> Vec<serde_json::Value>;
80}