feat: implement settings service with CRUD operations and integrate into app state
This commit is contained in:
@@ -20,9 +20,10 @@ async fn setup_app(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error
|
||||
|
||||
// Establish database connection
|
||||
let db = db::service::DbService::new(app_handle).await?;
|
||||
let services = services::ServiceFactory::create_services(db.get_connection().clone());
|
||||
|
||||
// Create app state with all services
|
||||
let app_state = AppState::new(db).await;
|
||||
let app_state = AppState::new(db, services).await;
|
||||
|
||||
// Manage the state with Tauri
|
||||
app.manage(app_state);
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use sea_orm::DatabaseConnection;
|
||||
|
||||
pub mod settings;
|
||||
|
||||
/// Service factory for creating service instances
|
||||
pub struct ServiceFactory;
|
||||
|
||||
pub struct ServiceFactoryResult {
|
||||
pub settings_service: Arc<dyn settings::service::SettingsService>,
|
||||
}
|
||||
|
||||
impl ServiceFactory {
|
||||
pub fn create_services(db: DatabaseConnection) -> () {
|
||||
()
|
||||
pub fn create_services(db: DatabaseConnection) -> ServiceFactoryResult {
|
||||
ServiceFactoryResult {
|
||||
settings_service: Arc::new(settings::service::SettingsServiceImpl::new(db)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
src-tauri/src/services/settings/mod.rs
Normal file
2
src-tauri/src/services/settings/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod service;
|
||||
pub mod types;
|
||||
159
src-tauri/src/services/settings/service.rs
Normal file
159
src-tauri/src/services/settings/service.rs
Normal file
@@ -0,0 +1,159 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use chrono::Utc;
|
||||
use log::warn;
|
||||
use sea_orm::{ActiveModelTrait, ActiveValue::Set, DatabaseConnection, EntityTrait};
|
||||
use struct_iterable::Iterable;
|
||||
|
||||
use crate::{
|
||||
db::{connection::ConnectionSource, entities::settings},
|
||||
errors::CommandResult,
|
||||
services::settings::types::settings::{Settings, UpdateSettingsInput},
|
||||
};
|
||||
|
||||
pub type SettingModel = settings::Model;
|
||||
|
||||
#[async_trait]
|
||||
pub trait SettingsService: Send + Sync {
|
||||
async fn get_settings(&self, tx: Option<&ConnectionSource<'_>>) -> CommandResult<Settings>;
|
||||
async fn update_setting(
|
||||
&self,
|
||||
key: String,
|
||||
value: String,
|
||||
tx: Option<&ConnectionSource<'_>>,
|
||||
) -> CommandResult<()>;
|
||||
async fn update_settings(
|
||||
&self,
|
||||
input: UpdateSettingsInput,
|
||||
tx: Option<&ConnectionSource<'_>>,
|
||||
) -> CommandResult<()>;
|
||||
async fn initialize_default_settings(
|
||||
&self,
|
||||
tx: Option<&ConnectionSource<'_>>,
|
||||
) -> CommandResult<()>;
|
||||
}
|
||||
|
||||
pub struct SettingsServiceImpl {
|
||||
db: DatabaseConnection,
|
||||
}
|
||||
|
||||
impl SettingsServiceImpl {
|
||||
pub fn new(db: DatabaseConnection) -> Self {
|
||||
Self { db }
|
||||
}
|
||||
|
||||
async fn get_setting(&self, key: &str, default: &str) -> String {
|
||||
crate::db::entities::settings::Entity::find_by_id(key.to_string())
|
||||
.one(&self.db)
|
||||
.await
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|s| s.value)
|
||||
.unwrap_or_else(|| default.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl SettingsService for SettingsServiceImpl {
|
||||
async fn get_settings(&self, tx: Option<&ConnectionSource<'_>>) -> CommandResult<Settings> {
|
||||
let settings_list = crate::db::entities::settings::Entity::find()
|
||||
.all(&tx.unwrap_or(&ConnectionSource::Connection(&self.db)))
|
||||
.await?;
|
||||
|
||||
let mut map = HashMap::new();
|
||||
for setting in settings_list {
|
||||
map.insert(setting.key, setting.value.unwrap_or_default());
|
||||
}
|
||||
|
||||
Ok(Settings::from(map))
|
||||
}
|
||||
|
||||
async fn update_setting(
|
||||
&self,
|
||||
key: String,
|
||||
value: String,
|
||||
tx: Option<&ConnectionSource<'_>>,
|
||||
) -> CommandResult<()> {
|
||||
let now = Utc::now().naive_utc();
|
||||
let tx_ = match tx {
|
||||
Some(tx) => tx,
|
||||
_ => &ConnectionSource::Connection(&self.db),
|
||||
};
|
||||
|
||||
let existing = crate::db::entities::settings::Entity::find_by_id(key.clone())
|
||||
.one(&tx_)
|
||||
.await?;
|
||||
|
||||
if let Some(setting) = existing {
|
||||
let mut active_model: settings::ActiveModel = setting.into();
|
||||
active_model.value = Set(Some(value));
|
||||
active_model.updated_at = Set(now);
|
||||
active_model.update(&tx_).await?;
|
||||
} else {
|
||||
let new_setting = settings::ActiveModel {
|
||||
key: Set(key),
|
||||
value: Set(Some(value)),
|
||||
updated_at: Set(now),
|
||||
};
|
||||
new_setting.insert(&tx_).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_settings(
|
||||
&self,
|
||||
input: UpdateSettingsInput,
|
||||
tx: Option<&ConnectionSource<'_>>,
|
||||
) -> CommandResult<()> {
|
||||
let tx_ = match tx {
|
||||
Some(tx) => tx,
|
||||
_ => &ConnectionSource::Connection(&self.db),
|
||||
};
|
||||
|
||||
for (key, value) in input.settings {
|
||||
self.update_setting(key, value, Some(tx_)).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn initialize_default_settings(
|
||||
&self,
|
||||
tx: Option<&ConnectionSource<'_>>,
|
||||
) -> CommandResult<()> {
|
||||
let default_settings = Settings::default();
|
||||
let settings_map: HashMap<String, String> = default_settings
|
||||
.iter()
|
||||
.filter_map(|(k, v)| -> Option<(String, String)> {
|
||||
let value_string = if let Some(s) = v.downcast_ref::<String>() {
|
||||
s.clone()
|
||||
} else if let Some(i) = v.downcast_ref::<i32>() {
|
||||
i.to_string()
|
||||
} else {
|
||||
warn!("Unsupported setting type for key '{k}'");
|
||||
return None;
|
||||
};
|
||||
Some((k.to_string(), value_string))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let tx_ = match tx {
|
||||
Some(tx) => tx,
|
||||
_ => &ConnectionSource::Connection(&self.db),
|
||||
};
|
||||
|
||||
for (key, value) in settings_map {
|
||||
let existing = crate::db::entities::settings::Entity::find_by_id(key.clone())
|
||||
.one(&tx_)
|
||||
.await?;
|
||||
if existing.is_none() {
|
||||
self.update_setting(key.clone(), value.clone(), Some(tx_))
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
83
src-tauri/src/services/settings/types/date_of_week.rs
Normal file
83
src-tauri/src/services/settings/types/date_of_week.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
use serde::Serialize;
|
||||
|
||||
const SUNDAY: &str = "sunday";
|
||||
const MONDAY: &str = "monday";
|
||||
const TUESDAY: &str = "tuesday";
|
||||
const WEDNESDAY: &str = "wednesday";
|
||||
const THURSDAY: &str = "thursday";
|
||||
const FRIDAY: &str = "friday";
|
||||
const SATURDAY: &str = "saturday";
|
||||
|
||||
#[derive(Debug, Serialize, Default)]
|
||||
pub enum DateOfWeek {
|
||||
#[default]
|
||||
Sunday,
|
||||
Monday,
|
||||
Tuesday,
|
||||
Wednesday,
|
||||
Thursday,
|
||||
Friday,
|
||||
Saturday,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DateOfWeek {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
DateOfWeek::Sunday => write!(f, "{}", SUNDAY),
|
||||
DateOfWeek::Monday => write!(f, "{}", MONDAY),
|
||||
DateOfWeek::Tuesday => write!(f, "{}", TUESDAY),
|
||||
DateOfWeek::Wednesday => write!(f, "{}", WEDNESDAY),
|
||||
DateOfWeek::Thursday => write!(f, "{}", THURSDAY),
|
||||
DateOfWeek::Friday => write!(f, "{}", FRIDAY),
|
||||
DateOfWeek::Saturday => write!(f, "{}", SATURDAY),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<String>> for DateOfWeek {
|
||||
fn from(s: Option<String>) -> Self {
|
||||
match s {
|
||||
Some(s) => match s.as_str() {
|
||||
SUNDAY => DateOfWeek::Sunday,
|
||||
MONDAY => DateOfWeek::Monday,
|
||||
TUESDAY => DateOfWeek::Tuesday,
|
||||
WEDNESDAY => DateOfWeek::Wednesday,
|
||||
THURSDAY => DateOfWeek::Thursday,
|
||||
FRIDAY => DateOfWeek::Friday,
|
||||
SATURDAY => DateOfWeek::Saturday,
|
||||
_ => DateOfWeek::default(),
|
||||
},
|
||||
None => DateOfWeek::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for DateOfWeek {
|
||||
fn from(s: String) -> Self {
|
||||
DateOfWeek::from(Some(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<i32>> for DateOfWeek {
|
||||
fn from(i: Option<i32>) -> Self {
|
||||
match i {
|
||||
Some(i) => match i {
|
||||
0 => DateOfWeek::Sunday,
|
||||
1 => DateOfWeek::Monday,
|
||||
2 => DateOfWeek::Tuesday,
|
||||
3 => DateOfWeek::Wednesday,
|
||||
4 => DateOfWeek::Thursday,
|
||||
5 => DateOfWeek::Friday,
|
||||
6 => DateOfWeek::Saturday,
|
||||
_ => DateOfWeek::default(),
|
||||
},
|
||||
None => DateOfWeek::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for DateOfWeek {
|
||||
fn from(i: i32) -> Self {
|
||||
DateOfWeek::from(Some(i))
|
||||
}
|
||||
}
|
||||
43
src-tauri/src/services/settings/types/display_mode.rs
Normal file
43
src-tauri/src/services/settings/types/display_mode.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use serde::Serialize;
|
||||
|
||||
const SYSTEM: &str = "system";
|
||||
const LIGHT: &str = "light";
|
||||
const DARK: &str = "dark";
|
||||
|
||||
#[derive(Debug, Serialize, Default)]
|
||||
pub enum DisplayMode {
|
||||
#[default]
|
||||
System,
|
||||
Light,
|
||||
Dark,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DisplayMode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
DisplayMode::System => write!(f, "{}", SYSTEM),
|
||||
DisplayMode::Light => write!(f, "{}", LIGHT),
|
||||
DisplayMode::Dark => write!(f, "{}", DARK),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<String>> for DisplayMode {
|
||||
fn from(s: Option<String>) -> Self {
|
||||
match s {
|
||||
Some(s) => match s.as_str() {
|
||||
SYSTEM => DisplayMode::System,
|
||||
LIGHT => DisplayMode::Light,
|
||||
DARK => DisplayMode::Dark,
|
||||
_ => DisplayMode::default(),
|
||||
},
|
||||
None => DisplayMode::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for DisplayMode {
|
||||
fn from(s: String) -> Self {
|
||||
DisplayMode::from(Some(s))
|
||||
}
|
||||
}
|
||||
43
src-tauri/src/services/settings/types/language.rs
Normal file
43
src-tauri/src/services/settings/types/language.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use serde::Serialize;
|
||||
|
||||
const ENGLISH: &str = "en";
|
||||
const TRADITIONAL_CHINESE: &str = "zh-TW";
|
||||
const CANTONESE: &str = "zh-HK";
|
||||
|
||||
#[derive(Debug, Serialize, Default)]
|
||||
pub enum Language {
|
||||
#[default]
|
||||
English,
|
||||
TraditionalChinese,
|
||||
Cantonese,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Language {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Language::English => write!(f, "{}", ENGLISH),
|
||||
Language::TraditionalChinese => write!(f, "{}", TRADITIONAL_CHINESE),
|
||||
Language::Cantonese => write!(f, "{}", CANTONESE),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<String>> for Language {
|
||||
fn from(s: Option<String>) -> Self {
|
||||
match s {
|
||||
Some(s) => match s.as_str() {
|
||||
ENGLISH => Language::English,
|
||||
TRADITIONAL_CHINESE => Language::TraditionalChinese,
|
||||
CANTONESE => Language::Cantonese,
|
||||
_ => Language::default(),
|
||||
},
|
||||
None => Language::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Language {
|
||||
fn from(s: String) -> Self {
|
||||
Language::from(Some(s))
|
||||
}
|
||||
}
|
||||
6
src-tauri/src/services/settings/types/mod.rs
Normal file
6
src-tauri/src/services/settings/types/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
pub mod date_of_week;
|
||||
pub mod display_mode;
|
||||
pub mod language;
|
||||
pub mod settings;
|
||||
pub mod theme;
|
||||
pub mod view;
|
||||
107
src-tauri/src/services/settings/types/settings.rs
Normal file
107
src-tauri/src/services/settings/types/settings.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use struct_iterable::Iterable;
|
||||
|
||||
use crate::services::settings::types::date_of_week::DateOfWeek;
|
||||
|
||||
use super::{display_mode::DisplayMode, language::Language, theme::Theme, view::View};
|
||||
|
||||
const LANGUAGE_KEY: &str = "language";
|
||||
const DEFAULT_CURRENCY_KEY: &str = "default_currency";
|
||||
const BASE_CURRENCY_KEY: &str = "base_currency";
|
||||
const TIMEZONE_KEY: &str = "timezone";
|
||||
const DEFAULT_VIEW_KEY: &str = "default_view";
|
||||
const DISPLAY_MODE_KEY: &str = "display_mode";
|
||||
const DECIMAL_PLACES_KEY: &str = "decimal_places";
|
||||
const DATE_FORMAT_KEY: &str = "date_format";
|
||||
const TIME_FORMAT_KEY: &str = "time_format";
|
||||
const THEME_KEY: &str = "theme";
|
||||
const WEEK_STARTS_ON_KEY: &str = "week_starts_on";
|
||||
const SCHEDULED_CHECK_INTERVAL_KEY: &str = "scheduled_check_interval";
|
||||
|
||||
const DEFAULT_DECIMAL_PLACES: i32 = 2;
|
||||
const DEFAULT_SCHEDULED_CHECK_INTERVAL: i32 = 1;
|
||||
|
||||
#[derive(Debug, Serialize, Iterable)]
|
||||
pub struct Settings {
|
||||
pub language: Language,
|
||||
pub default_currency: String,
|
||||
pub base_currency: String,
|
||||
pub timezone: String,
|
||||
pub default_view: View,
|
||||
pub display_mode: DisplayMode,
|
||||
pub decimal_places: i32,
|
||||
pub date_format: String,
|
||||
pub time_format: String,
|
||||
pub theme: Theme,
|
||||
pub week_starts_on: DateOfWeek,
|
||||
pub scheduled_check_interval: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct UpdateSettingsInput {
|
||||
pub settings: std::collections::HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Settings {
|
||||
language: Language::default(),
|
||||
default_currency: "HKD".to_string(),
|
||||
base_currency: "HKD".to_string(),
|
||||
timezone: "auto".to_string(),
|
||||
default_view: View::default(),
|
||||
display_mode: DisplayMode::default(),
|
||||
decimal_places: DEFAULT_DECIMAL_PLACES,
|
||||
date_format: "YYYY-MM-DD".to_string(),
|
||||
time_format: "24h".to_string(),
|
||||
theme: Theme::default(),
|
||||
week_starts_on: DateOfWeek::default(),
|
||||
scheduled_check_interval: DEFAULT_SCHEDULED_CHECK_INTERVAL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::collections::HashMap<String, String>> for Settings {
|
||||
fn from(map: std::collections::HashMap<String, String>) -> Self {
|
||||
let default_settings = Settings::default();
|
||||
Settings {
|
||||
language: map.get(LANGUAGE_KEY).cloned().into(),
|
||||
default_currency: map
|
||||
.get(DEFAULT_CURRENCY_KEY)
|
||||
.cloned()
|
||||
.unwrap_or(default_settings.default_currency),
|
||||
base_currency: map
|
||||
.get(BASE_CURRENCY_KEY)
|
||||
.cloned()
|
||||
.unwrap_or(default_settings.base_currency),
|
||||
timezone: map
|
||||
.get(TIMEZONE_KEY)
|
||||
.cloned()
|
||||
.unwrap_or(default_settings.timezone),
|
||||
default_view: map.get(DEFAULT_VIEW_KEY).cloned().into(),
|
||||
display_mode: map.get(DISPLAY_MODE_KEY).cloned().into(),
|
||||
decimal_places: map
|
||||
.get(DECIMAL_PLACES_KEY)
|
||||
.cloned()
|
||||
.unwrap_or(default_settings.decimal_places.to_string())
|
||||
.parse()
|
||||
.unwrap_or(DEFAULT_DECIMAL_PLACES),
|
||||
date_format: map
|
||||
.get(DATE_FORMAT_KEY)
|
||||
.cloned()
|
||||
.unwrap_or(default_settings.date_format),
|
||||
time_format: map
|
||||
.get(TIME_FORMAT_KEY)
|
||||
.cloned()
|
||||
.unwrap_or(default_settings.time_format),
|
||||
theme: map.get(THEME_KEY).cloned().into(),
|
||||
week_starts_on: map.get(WEEK_STARTS_ON_KEY).cloned().into(),
|
||||
scheduled_check_interval: map
|
||||
.get(SCHEDULED_CHECK_INTERVAL_KEY)
|
||||
.cloned()
|
||||
.unwrap_or(default_settings.scheduled_check_interval.to_string())
|
||||
.parse()
|
||||
.unwrap_or(DEFAULT_SCHEDULED_CHECK_INTERVAL),
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src-tauri/src/services/settings/types/theme.rs
Normal file
43
src-tauri/src/services/settings/types/theme.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use serde::Serialize;
|
||||
|
||||
const SYSTEM: &str = "system";
|
||||
const LIGHT: &str = "light";
|
||||
const DARK: &str = "dark";
|
||||
|
||||
#[derive(Debug, Serialize, Default)]
|
||||
pub enum Theme {
|
||||
#[default]
|
||||
System,
|
||||
Light,
|
||||
Dark,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Theme {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Theme::System => write!(f, "{}", SYSTEM),
|
||||
Theme::Light => write!(f, "{}", LIGHT),
|
||||
Theme::Dark => write!(f, "{}", DARK),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<String>> for Theme {
|
||||
fn from(s: Option<String>) -> Self {
|
||||
match s {
|
||||
Some(s) => match s.as_str() {
|
||||
SYSTEM => Theme::System,
|
||||
LIGHT => Theme::Light,
|
||||
DARK => Theme::Dark,
|
||||
_ => Theme::default(),
|
||||
},
|
||||
None => Theme::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Theme {
|
||||
fn from(s: String) -> Self {
|
||||
Theme::from(Some(s))
|
||||
}
|
||||
}
|
||||
39
src-tauri/src/services/settings/types/view.rs
Normal file
39
src-tauri/src/services/settings/types/view.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use serde::Serialize;
|
||||
|
||||
const COMBINED: &str = "combined";
|
||||
const SPLIT: &str = "split";
|
||||
|
||||
#[derive(Debug, Default, Serialize)]
|
||||
pub enum View {
|
||||
#[default]
|
||||
Combined,
|
||||
Split,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for View {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
View::Combined => write!(f, "{}", COMBINED),
|
||||
View::Split => write!(f, "{}", SPLIT),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<String>> for View {
|
||||
fn from(s: Option<String>) -> Self {
|
||||
match s {
|
||||
Some(s) => match s.as_str() {
|
||||
COMBINED => View::Combined,
|
||||
SPLIT => View::Split,
|
||||
_ => View::default(),
|
||||
},
|
||||
None => View::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for View {
|
||||
fn from(s: String) -> Self {
|
||||
View::from(Some(s))
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,28 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{db::service::DbService, services::ServiceFactory};
|
||||
use crate::{
|
||||
db::service::DbService,
|
||||
services::{ServiceFactoryResult, settings::service::SettingsService},
|
||||
};
|
||||
pub struct AppState {
|
||||
db: DbService,
|
||||
settings_service: Arc<dyn SettingsService>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
/// Create a new AppState with all services initialized
|
||||
pub async fn new(db: DbService) -> Self {
|
||||
let () = ServiceFactory::create_services(db.get_connection().clone());
|
||||
Self { db }
|
||||
pub async fn new(db: DbService, services: ServiceFactoryResult) -> Self {
|
||||
Self {
|
||||
db,
|
||||
settings_service: services.settings_service,
|
||||
}
|
||||
}
|
||||
/// Get the database service
|
||||
pub fn db(&self) -> &DbService {
|
||||
&self.db
|
||||
}
|
||||
/// Get the settings service
|
||||
pub fn settings_service(&self) -> &Arc<dyn SettingsService> {
|
||||
&self.settings_service
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user