From 3223d93cb3c77ab02aa0a35f2a8314e447cee9a4 Mon Sep 17 00:00:00 2001 From: Benedikt Peetz Date: Thu, 9 Jul 2026 21:43:23 +0200 Subject: chore: Separate daemon, client, server, and lib into crates --- crates/server/src/database/mod.rs | 99 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 crates/server/src/database/mod.rs (limited to 'crates/server/src/database/mod.rs') diff --git a/crates/server/src/database/mod.rs b/crates/server/src/database/mod.rs new file mode 100644 index 00000000..43fe5c3b --- /dev/null +++ b/crates/server/src/database/mod.rs @@ -0,0 +1,99 @@ +pub(crate) mod db; +pub(crate) mod models; + +use std::fmt::{Debug, Display}; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug)] +pub(crate) enum DbError { + NotFound, + Other(eyre::Report), +} + +impl Display for DbError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::NotFound => write!(f, "Not found"), + Self::Other(report) => write!(f, "Other: {report}"), + } + } +} + +impl From for DbError { + fn from(error: time::error::ComponentRange) -> Self { + Self::Other(error.into()) + } +} + +impl From for DbError { + fn from(error: time::error::Error) -> Self { + Self::Other(error.into()) + } +} + +impl From for DbError { + fn from(error: sqlx::Error) -> Self { + match error { + sqlx::Error::RowNotFound => Self::NotFound, + error => Self::Other(error.into()), + } + } +} + +impl std::error::Error for DbError {} + +pub(crate) type DbResult = Result; + +#[derive(Debug, PartialEq)] +pub(crate) enum DbType { + Postgres, + Unknown, +} + +#[derive(Clone, Deserialize, Serialize)] +pub(crate) struct DbSettings { + pub(crate) db_uri: String, + + /// Optional URI for read replicas. If set, read-only queries will use this connection. + pub(crate) read_db_uri: Option, +} + +impl DbSettings { + pub(crate) fn db_type(&self) -> DbType { + if self.db_uri.starts_with("postgres://") || self.db_uri.starts_with("postgresql://") { + DbType::Postgres + } else { + DbType::Unknown + } + } +} + +fn redact_db_uri(uri: &str) -> String { + url::Url::parse(uri).map_or_else( + |_| uri.to_string(), + |mut url| { + url.set_password(Some("****")).expect("should be possible"); + url.to_string() + }, + ) +} + +// Do our best to redact passwords so they're not logged in the event of an error. +impl Debug for DbSettings { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.db_type() == DbType::Postgres { + let redacted_uri = redact_db_uri(&self.db_uri); + let redacted_read_uri = self.read_db_uri.as_ref().map(|uri| redact_db_uri(uri)); + f.debug_struct("DbSettings") + .field("db_uri", &redacted_uri) + .field("read_db_uri", &redacted_read_uri) + .finish() + } else { + f.debug_struct("DbSettings") + .field("db_uri", &self.db_uri) + .field("read_db_uri", &self.read_db_uri) + .finish() + } + } +} -- cgit v1.3.1