slave_framework/
database.rs1use std::sync::Arc;
8
9use libsql::{Builder, Connection};
10
11use crate::{Error, Result};
12
13pub const URL_ENV: &str = "TURSO_DATABASE_URL";
15pub const TOKEN_ENV: &str = "TURSO_AUTH_TOKEN";
17
18pub const SETUP_HINT: &str = "Create a database with `turso db create <name>`, then set \
20 TURSO_DATABASE_URL (`turso db show --url <name>`) and TURSO_AUTH_TOKEN \
21 (`turso db tokens create <name>`) in .env.";
22
23#[derive(Clone)]
25pub struct DatabaseConfig {
26 pub url: String,
27 pub auth_token: String,
28}
29
30impl std::fmt::Debug for DatabaseConfig {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 f.debug_struct("DatabaseConfig")
33 .field("url", &self.url)
34 .field("auth_token", &"<redacted>")
35 .finish()
36 }
37}
38
39impl DatabaseConfig {
40 pub fn from_env() -> Result<Self> {
43 let url = std::env::var(URL_ENV)
44 .ok()
45 .filter(|url| !url.trim().is_empty())
46 .ok_or(Error::MissingDatabaseUrl(URL_ENV))?;
47 let auth_token = std::env::var(TOKEN_ENV).unwrap_or_default();
48 Ok(Self { url, auth_token })
49 }
50}
51
52#[derive(Clone)]
57pub struct Database {
58 inner: Arc<libsql::Database>,
59 url: Arc<str>,
60}
61
62impl std::fmt::Debug for Database {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 f.debug_struct("Database").field("url", &self.url).finish()
65 }
66}
67
68impl Database {
69 pub async fn open(config: &DatabaseConfig) -> Result<Self> {
72 let inner = Builder::new_remote(config.url.clone(), config.auth_token.clone())
73 .build()
74 .await?;
75 Ok(Self {
76 inner: Arc::new(inner),
77 url: config.url.as_str().into(),
78 })
79 }
80
81 pub async fn from_env() -> Result<Self> {
83 Self::open(&DatabaseConfig::from_env()?).await
84 }
85
86 pub fn url(&self) -> &str {
88 &self.url
89 }
90
91 pub async fn connect(&self) -> Result<Connection, libsql::Error> {
93 let conn = self.inner.connect()?;
94 conn.execute("PRAGMA foreign_keys = ON", ()).await?;
95 Ok(conn)
96 }
97}