Skip to main content

SqlConnector

Trait SqlConnector 

Source
pub trait SqlConnector:
    Send
    + Sync
    + 'static {
    // Required methods
    fn dialect(&self) -> Dialect;
    fn execute<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        sql: &'life1 str,
        params: &'life2 [(String, Value)],
    ) -> Pin<Box<dyn Future<Output = Result<Vec<Value>, ConnectorError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
    fn schema_text<'life0, 'async_trait>(
        &'life0 self,
    ) -> Pin<Box<dyn Future<Output = Result<String, ConnectorError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
}
Expand description

Three-method SQL connector trait — Phase 84 ships the full trait surface.

Phase 83 shipped a 2-method MVP (dialect() + schema_text()); Phase 84 (CONN-01) lands execute() between them now that the per-backend connectors validate the row/error/parameter shape. The trait is the stable contract the per-backend crates (pmcp-toolkit-postgres, pmcp-toolkit-mysql, pmcp-toolkit-athena, plus the sqlite feature SqliteConnector) implement.

§Semver-evolution plan

This trait WILL grow additively in a future minor release with:

  • execute_stream(sql, params) -> impl Stream<Item = Result<Value>>, shipped with a default body backed by execute(...).map(stream::iter) so it is semver-compatible on a Send + Sync + 'static trait — for the large-result-scan case (e.g. an Athena warehousing tool). Deferred per D-02 because no v2.2 reference scenario needs it.
  • Transaction support as a separate SqlTransactional trait extension, when a real consumer needs it. Deferred per D-02 — the v2.2 reference scenarios are read-only and Athena has no real transaction model.

The variants on Dialect and ConnectorError are #[non_exhaustive] so they can be extended additively without a semver break.

§Example

A minimal connector implementing all three methods. The example defines a LOCAL dummy struct — it deliberately does NOT reference any downstream per-backend crate, because those depend on pmcp-server-toolkit and would create a circular doctest dependency (REVIEWS H6).

use pmcp_server_toolkit::sql::{SqlConnector, Dialect, ConnectorError};
use async_trait::async_trait;
use serde_json::Value;

struct Dummy;

#[async_trait]
impl SqlConnector for Dummy {
    fn dialect(&self) -> Dialect { Dialect::Sqlite }
    async fn execute(&self, _sql: &str, _params: &[(String, Value)])
        -> Result<Vec<Value>, ConnectorError> {
        Ok(vec![])
    }
    async fn schema_text(&self) -> Result<String, ConnectorError> {
        Ok(String::new())
    }
}

Required Methods§

Source

fn dialect(&self) -> Dialect

Identify the dialect for prompt assembly + placeholder translation.

Source

fn execute<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, sql: &'life1 str, params: &'life2 [(String, Value)], ) -> Pin<Box<dyn Future<Output = Result<Vec<Value>, ConnectorError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Execute a query and return one serde_json::Value per result row.

sql is the canonical statement (placeholders in the toolkit’s :name form); params is a slice of named (name, value) pairs the caller controls the order of (D-03). Per-backend impls translate placeholders to their dialect via translate_placeholders and bind from params, then convert driver-native rows into JSON objects (D-01).

Each returned Value is typically a JSON object keyed by column name — the exact shape MCP transport needs to populate the tools/call response’s structuredContent field (D-06).

§Errors

Returns a ConnectorError when the backend cannot connect (ConnectorError::Connection), the driver fails (ConnectorError::Driver), the query is rejected (ConnectorError::Query), or a parameter cannot be bound (ConnectorError::ParameterBind).

Source

fn schema_text<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<String, ConnectorError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Render the backend’s schema as DDL or equivalent text for inclusion in the code-mode prompt. Phase 84 impls drive this from information_schema, the Glue catalog, or sqlite_master per dialect.

Implementations should keep output BOUNDED — token-budget the schema before returning. The toolkit does not truncate (T-83-07-03).

§Errors

Returns a ConnectorError when the backend cannot enumerate its schema (I/O failure, permission denied, missing catalog, etc.).

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§