Protocol adapters handle protocol-specific request/response formatting and query language parsing. This guide shows how to add support for a new query protocol.
A protocol adapter:
- Parses incoming requests (GET/POST parameters, headers, etc.)
- Translates queries to internal format
- Formats query results for the protocol
- Defines protocol-specific endpoints
Create src/drivers/query/adapters/clickhouse_http.rs:
/// ClickHouse HTTP protocol adapter
pub struct ClickHouseHttpAdapter {
config: AdapterConfig,
}
impl ClickHouseHttpAdapter {
...
}
#[async_trait]
impl QueryRequestAdapter for ClickHouseHttpAdapter {
...
}
#[async_trait]
impl QueryResponseAdapter for ClickHouseHttpAdapter {
...
}
#[async_trait]
impl HttpProtocolAdapter for ClickHouseHttpAdapter {
...
}Update src/data_model/enums.rs to add the new protocol:
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QueryProtocol {
...
ClickHouseHttp, // Add this
}Update src/drivers/query/adapters/mod.rs:
pub mod clickhouse_http;
pub use clickhouse_http::ClickHouseHttpAdapter;Update src/drivers/query/adapters/factory.rs:
pub fn create_http_adapter(config: AdapterConfig) -> Arc<dyn HttpProtocolAdapter> {
match config.protocol {
...
QueryProtocol::ClickHouseHttp => { // Add this
Arc::new(ClickHouseHttpAdapter::new(config))
}
}
}Update src/drivers/query/adapters/config.rs:
impl AdapterConfig {
pub fn clickhouse_http(fallback_url: String, forward_unsupported: bool) -> Self {
...
}
}Add tests in clickhouse_http.rs:
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_parse_get_request() {
...
}
}parse_get_request()- Parse GET requestsparse_post_request()- Parse POST requestsget_query_endpoint()- Return endpoint path
format_success_response()- Format successful query resultsformat_error_response()- Format errorsformat_unsupported_query_response()- Format unsupported query errors
adapter_name()- Return adapter name for loggingget_runtime_info_path()- Return health/status endpoint pathhandle_runtime_info()- Handle health/status requests
- Don't implement query execution in the adapter - that's the engine's job
- Don't hard-code URLs or configuration - use
AdapterConfig - Handle both GET and POST requests appropriately
- Return protocol-specific error formats
- Use existing types from
traits.rs(ParsedQueryRequest,QueryExecutionResult)