use crate::config::ClientConfig;
use crate::core::{Middleware, SupabaseClient, SupabaseInner};
use crate::error::{Result, SupaError};
use reqwest::Client;
use std::sync::Arc;
use url::Url;
pub struct SupabaseClientBuilder {
pub(crate) url: Option<String>,
pub(crate) key: Option<String>,
pub(crate) config: ClientConfig,
pub(crate) middlewares: Vec<Arc<dyn Middleware>>,
pub(crate) is_service_role: bool,
#[cfg(feature = "auth")]
pub(crate) session_store: Option<Arc<dyn crate::auth_store::SessionStore>>,
}
impl Default for SupabaseClientBuilder {
fn default() -> Self {
Self::new()
}
}
impl SupabaseClientBuilder {
pub fn new() -> Self {
Self {
url: None,
key: None,
config: ClientConfig::default(),
middlewares: Vec::new(),
is_service_role: false,
#[cfg(feature = "auth")]
session_store: None,
}
}
pub fn url(mut self, url: impl Into<String>) -> Self {
self.url = Some(url.into());
self
}
pub fn key(mut self, key: impl Into<String>) -> Self {
self.key = Some(key.into());
self
}
pub fn timeout(mut self, secs: u64) -> Self {
self.config.timeout_secs = secs;
self
}
pub fn max_retries(mut self, retries: u32) -> Self {
self.config.max_retries = retries;
self
}
#[cfg(feature = "auth")]
pub fn with_session_store<S: crate::auth_store::SessionStore + 'static>(
mut self,
store: S,
) -> Self {
self.session_store = Some(Arc::new(store));
self
}
pub fn middleware<M: Middleware + 'static>(mut self, middleware: M) -> Self {
self.middlewares.push(Arc::new(middleware));
self
}
pub fn service_role(mut self, is_service_role: bool) -> Self {
self.is_service_role = is_service_role;
self
}
pub fn build(self) -> Result<SupabaseClient> {
let url_str = self.url.ok_or_else(|| SupaError::ClientError {
message: "Supabase URL is required".to_string(),
})?;
let key = self.key.ok_or_else(|| SupaError::ClientError {
message: "Supabase Key is required".to_string(),
})?;
let http = Client::builder()
.timeout(std::time::Duration::from_secs(self.config.timeout_secs))
.build()
.map_err(|e| SupaError::ClientError {
message: format!("Failed to build HTTP client: {}", e),
})?;
let inner = SupabaseInner {
url: Url::parse(&url_str)?,
key,
http,
config: self.config,
middlewares: self.middlewares,
session: std::sync::RwLock::new(None),
is_service_role: self.is_service_role,
#[cfg(feature = "auth")]
session_store: std::sync::RwLock::new(self.session_store),
schema: std::sync::RwLock::new(None),
};
let client = SupabaseClient {
inner: Arc::new(inner),
};
#[cfg(feature = "auth")]
{
let store_lock = client.inner.session_store.read().unwrap();
if let Some(store) = store_lock.as_ref() {
if let Ok(Some(session)) = store.load() {
if let Ok(mut sess_lock) = client.inner.session.write() {
*sess_lock = Some(session);
}
}
}
}
Ok(client)
}
}