caretta-sync/core/src/global/database_connection.rs

122 lines
3.7 KiB
Rust
Raw Normal View History

2025-08-20 06:50:35 +09:00
use std::path::{Path, PathBuf};
2025-06-19 07:24:44 +09:00
2025-08-23 08:55:25 +09:00
use dirs::cache_dir;
2025-06-19 07:24:44 +09:00
use sea_orm::{ConnectOptions, Database, DbErr, DatabaseConnection};
use sea_orm_migration::MigratorTrait;
2025-08-20 12:39:29 +09:00
use crate::{cache::migration::CacheMigrator, config::StorageConfig, error::Error};
2025-06-19 07:24:44 +09:00
use tokio::sync::OnceCell;
2025-08-20 12:39:29 +09:00
pub static DATABASE_CONNECTIONS: GlobalDatabaseConnections = GlobalDatabaseConnections::const_new();
2025-08-20 06:50:35 +09:00
2025-08-20 12:39:29 +09:00
pub struct DatabaseConnections<'a> {
pub data: &'a DatabaseConnection,
pub cache: &'a DatabaseConnection
2025-08-20 06:50:35 +09:00
}
2025-08-20 12:39:29 +09:00
pub struct GlobalDatabaseConnections {
data: OnceCell<DatabaseConnection>,
cache: OnceCell<DatabaseConnection>,
2025-06-20 07:28:51 +09:00
}
2025-06-19 07:24:44 +09:00
2025-08-20 12:39:29 +09:00
impl GlobalDatabaseConnections {
pub const fn const_new() -> Self {
2025-06-20 08:42:02 +09:00
Self {
2025-08-20 12:39:29 +09:00
data: OnceCell::const_new(),
cache: OnceCell::const_new()
2025-06-20 08:42:02 +09:00
}
}
2025-08-20 12:39:29 +09:00
pub fn get_data(&'static self) -> Option<&'static DatabaseConnection> {
self.data.get()
}
pub fn get_data_unchecked(&'static self) -> &'static DatabaseConnection {
self.get_data().expect("Global data database connection should initialized before access!")
}
pub fn get_cache(&'static self) -> Option<&'static DatabaseConnection> {
self.cache.get()
}
pub fn get_cache_unchecked(&'static self) -> &'static DatabaseConnection {
self.get_cache().expect("Global cache database connection should initialized before access!")
2025-08-20 06:50:35 +09:00
}
2025-08-20 12:39:29 +09:00
fn get_data_file_path<T>(config: &T) -> PathBuf
2025-08-20 06:50:35 +09:00
where
T: AsRef<StorageConfig>
{
2025-08-22 07:56:26 +09:00
config.as_ref().data_directory.join("data.sqlite")
2025-08-20 12:39:29 +09:00
}
fn get_cache_file_path<T>(config: &T) -> PathBuf
where
T: AsRef<StorageConfig>
{
2025-08-22 07:56:26 +09:00
config.as_ref().cache_directory.join("cache.sqlite")
2025-08-20 12:39:29 +09:00
}
fn get_url_unchecked<T>(path: T) -> String
where
T: AsRef<Path>
{
"sqlite://".to_string() + path.as_ref().as_os_str().to_str().expect("Failed to convert path to string!") + "?mode=rwc"
2025-08-20 06:50:35 +09:00
}
2025-08-20 12:39:29 +09:00
async fn get_or_init_database_connection_unchecked<T, U>(cell: &OnceCell<DatabaseConnection>, options: T, _: U ) -> &DatabaseConnection
where
T: Into<ConnectOptions>,
U: MigratorTrait
{
cell.get_or_init(|| async {
let db = Database::connect(options.into()).await.unwrap();
U::up(&db, None).await.unwrap();
db
}).await
2025-06-20 08:42:02 +09:00
}
2025-08-20 12:39:29 +09:00
pub async fn get_or_init_unchecked<T, U>(&'static self, config: T, _migrator: U) -> DatabaseConnections
2025-06-20 08:42:02 +09:00
where
2025-08-20 06:50:35 +09:00
T: AsRef<StorageConfig>,
2025-08-20 12:39:29 +09:00
U: MigratorTrait,
2025-06-20 08:42:02 +09:00
{
2025-08-23 08:55:25 +09:00
let data_path = Self::get_data_file_path(&config);
if let Some(x) = data_path.parent() {
std::fs::create_dir_all(x).expect("Failed to create directory for data database");
}
let cache_path = Self::get_cache_file_path(&config);
if let Some(x) = cache_path.parent() {
std::fs::create_dir_all(x).expect("Failed to create directory for cache database");
}
2025-08-20 12:39:29 +09:00
DatabaseConnections{
data: Self::get_or_init_database_connection_unchecked(
&self.data,
2025-08-23 08:55:25 +09:00
Self::get_url_unchecked(data_path),
2025-08-20 12:39:29 +09:00
_migrator
).await,
cache: Self::get_or_init_database_connection_unchecked(
&self.cache,
2025-08-23 08:55:25 +09:00
Self::get_url_unchecked(cache_path),
2025-08-20 12:39:29 +09:00
CacheMigrator
).await,
}
2025-06-20 08:42:02 +09:00
}
2025-06-20 07:28:51 +09:00
}
2025-06-22 11:29:44 +09:00
#[cfg(test)]
pub use tests::*;
#[cfg(test)]
mod tests {
use super::*;
2025-08-20 06:50:35 +09:00
use crate::{cache::migration::CacheMigrator, data::migration::DataMigrator, global::CONFIG, tests::{TEST_CONFIG}};
2025-06-22 11:29:44 +09:00
2025-08-20 12:39:29 +09:00
#[tokio::test]
pub async fn get_or_init_database() {
DATABASE_CONNECTIONS.get_or_init_unchecked(&*TEST_CONFIG, DataMigrator).await;
2025-06-22 11:29:44 +09:00
}
2025-08-20 12:39:29 +09:00
}