use async_trait::async_trait;
use datafusion::execution::context::SessionContext;
use crate::error::{Error, Result};
use crate::response::ListSummary;
#[async_trait]
pub trait Backend: Send + Sync {
fn connection(&self) -> &ConnectionMetadata;
async fn prepare_session(&self, _session: &SessionContext) -> Result<()> { Ok(()) }
async fn list(&self, _database: Option<&str>) -> Result<ListSummary> {
Err(Error::UnsupportedConnector("Connector does not support table listing".into()))
}
}
impl std::fmt::Debug for &dyn Backend {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Backend").field("connection", self.connection()).finish()
}
}
#[non_exhaustive]
#[derive(
Debug,
Clone,
PartialEq,
Eq,
Hash,
serde::Serialize,
serde::Deserialize,
utoipa::ToResponse,
utoipa::ToSchema,
)]
pub struct BackendMetadata {
pub kind: ConnectionKind,
pub capabilities: Vec<Capability>,
}
impl BackendMetadata {
pub fn new(kind: ConnectionKind) -> Self {
Self { kind, capabilities: vec![Capability::ExecuteSql, Capability::List] }
}
#[must_use]
pub fn with_capabilities(mut self, capabilities: Vec<Capability>) -> Self {
self.capabilities = capabilities;
self
}
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
Hash,
serde::Serialize,
serde::Deserialize,
utoipa::ToResponse,
utoipa::ToSchema,
)]
pub struct ConnectionMetadata {
pub id: String,
pub name: String,
pub catalog: Option<String>,
pub metadata: BackendMetadata,
}
impl ConnectionMetadata {
pub fn has(&self, capability: Capability) -> bool {
self.metadata.capabilities.contains(&capability)
}
}
#[non_exhaustive]
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, utoipa::ToSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum Capability {
ExecuteSql,
List,
}
#[non_exhaustive]
#[derive(
Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, utoipa::ToSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum ConnectionKind {
ObjectStore,
Database,
Other(String),
}
impl AsRef<str> for ConnectionKind {
fn as_ref(&self) -> &str {
match self {
ConnectionKind::ObjectStore => "object_store",
ConnectionKind::Database => "database",
ConnectionKind::Other(kind) => kind,
}
}
}