add public interface for synced database

This commit is contained in:
Nikita Sivukhin
2025-07-30 00:57:27 +04:00
parent fedecd8e60
commit 43bbc34455

View File

@@ -0,0 +1,99 @@
use std::path::PathBuf;
use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder};
use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor};
use crate::{
database_inner::{DatabaseInner, Rows},
errors::Error,
filesystem::tokio::TokioFilesystem,
sync_server::turso::{TursoSyncServer, TursoSyncServerOpts},
Result,
};
/// [Database] expose public interface for synced database from [DatabaseInner] private implementation
///
/// This layer also serves a purpose of "gluing" together all component for real use,
/// because [DatabaseInner] abstracts things away in order to simplify testing
pub struct Database(DatabaseInner<TursoSyncServer, TokioFilesystem>);
pub struct Builder {
path: String,
sync_url: String,
auth_token: Option<String>,
encryption_key: Option<String>,
connector: Option<HttpsConnector<HttpConnector>>,
}
impl Builder {
pub fn new_synced(path: &str, sync_url: &str, auth_token: Option<String>) -> Self {
Self {
path: path.to_string(),
sync_url: sync_url.to_string(),
auth_token: auth_token,
encryption_key: None,
connector: None,
}
}
pub fn with_encryption_key(self, encryption_key: &str) -> Self {
Self {
encryption_key: Some(encryption_key.to_string()),
..self
}
}
pub fn with_connector(self, connector: HttpsConnector<HttpConnector>) -> Self {
Self {
connector: Some(connector),
..self
}
}
pub async fn build(self) -> Result<Database> {
let path = PathBuf::try_from(self.path)
.map_err(|e| Error::DatabaseSyncError(format!("invalid synced database path: {e}")))?;
let connector = self
.connector
.map(Ok)
.unwrap_or_else(|| default_connector())?;
let executor = TokioExecutor::new();
let client = hyper_util::client::legacy::Builder::new(executor).build(connector);
let sync_server = TursoSyncServer::new(
client,
TursoSyncServerOpts {
sync_url: self.sync_url,
auth_token: self.auth_token,
encryption_key: self.encryption_key,
pull_batch_size: None,
},
)?;
let filesystem = TokioFilesystem();
let inner = DatabaseInner::new(filesystem, sync_server, &path).await?;
Ok(Database(inner))
}
}
impl Database {
pub async fn sync_full(&mut self) -> Result<()> {
self.0.sync_full().await
}
pub async fn sync_from_remote(&mut self) -> Result<()> {
self.0.sync_from_remote().await
}
pub async fn sync_to_remote(&mut self) -> Result<()> {
self.0.sync_to_remote().await
}
pub async fn execute(&self, sql: &str, params: impl turso::IntoParams) -> Result<u64> {
self.0.execute(sql, params).await
}
pub async fn query(&self, sql: &str, params: impl turso::IntoParams) -> Result<Rows> {
self.0.query(sql, params).await
}
}
pub fn default_connector() -> Result<HttpsConnector<HttpConnector>> {
Ok(HttpsConnectorBuilder::new()
.with_native_roots()
.map_err(|e| Error::DatabaseSyncError(format!("unable to configure CA roots: {}", e)))?
.https_or_http()
.enable_http1()
.build())
}