use std::{ops::Deref, sync::Arc};
use sea_orm::{DatabaseConnection, DbErr};
use crate::Depot;
#[derive(Clone, Debug, Default)]
pub struct DbService {
master: MrConn,
replica: MrConn,
}
#[derive(Clone, Debug)]
#[allow(clippy::exhaustive_enums)]
pub enum MrConn {
Master(Arc<DatabaseConnection>),
Replica(Arc<DatabaseConnection>),
}
impl Default for MrConn {
fn default() -> Self {
MrConn::Master(Default::default())
}
}
impl Deref for MrConn {
type Target = DatabaseConnection;
fn deref(&self) -> &Self::Target {
self.db()
}
}
impl MrConn {
pub fn db(&self) -> &DatabaseConnection {
match self {
MrConn::Master(arc) => arc,
MrConn::Replica(arc) => arc,
}
}
pub fn expand(&self) -> (&DatabaseConnection, bool) {
match self {
MrConn::Master(arc) => (arc, true),
MrConn::Replica(arc) => (arc, false),
}
}
}
impl DbService {
pub async fn new(master_url: &str, replica_url: &str) -> Result<Self, DbErr> {
let master = Arc::new(sea_orm::Database::connect(master_url).await?);
let replica = if master_url == replica_url {
master.clone()
} else {
Arc::new(sea_orm::Database::connect(replica_url).await?)
};
Ok(DbService {
master: MrConn::Master(master),
replica: MrConn::Replica(replica),
})
}
pub const fn from(master: Arc<DatabaseConnection>, replica: Arc<DatabaseConnection>) -> Self {
Self {
master: MrConn::Master(master),
replica: MrConn::Replica(replica),
}
}
#[inline(always)]
pub fn write_db(&self, depot: &mut Depot) -> &DatabaseConnection {
self.master_db(Some(depot))
}
#[inline(always)]
pub fn read_db<'a, 'b: 'a>(&'b self, depot: &'a mut Depot) -> &'a DatabaseConnection {
self.upstream_or_replica_db(depot)
}
pub fn master_db(&self, depot: Option<&mut Depot>) -> &DatabaseConnection {
if let Some(depot) = depot {
depot.inject(self.master.clone());
}
&self.master
}
pub fn replica_db(&self, depot: Option<&mut Depot>) -> &DatabaseConnection {
if let Some(depot) = depot {
depot.inject(self.replica.clone());
}
&self.replica
}
pub fn upstream_or_master_db<'a, 'b: 'a>(&'b self, depot: &'a mut Depot) -> &'a MrConn {
depot.obtain().unwrap_or(&self.master)
}
pub fn upstream_or_replica_db<'a, 'b: 'a>(&'b self, depot: &'a mut Depot) -> &'a MrConn {
depot.obtain().unwrap_or(&self.replica)
}
}