Skip to main content

track_core/
settings_repository.rs

1use serde::{de::DeserializeOwned, Serialize};
2use sqlx::Row;
3
4use crate::database::DatabaseContext;
5use crate::errors::{ErrorCode, TrackError};
6
7#[derive(Debug, Clone)]
8pub struct SettingsRepository {
9    database: DatabaseContext,
10}
11
12impl SettingsRepository {
13    pub fn new(database: Option<DatabaseContext>) -> Result<Self, TrackError> {
14        let database = match database {
15            Some(database) => database,
16            None => DatabaseContext::new(None)?,
17        };
18        database.initialize()?;
19
20        Ok(Self { database })
21    }
22
23    pub fn load_json<T>(&self, key: &str) -> Result<Option<T>, TrackError>
24    where
25        T: DeserializeOwned + Send + 'static,
26    {
27        let key = key.to_owned();
28        self.database.run(move |connection| {
29            Box::pin(async move {
30                let row =
31                    sqlx::query("SELECT setting_json FROM backend_settings WHERE setting_key = ?1")
32                        .bind(&key)
33                        .fetch_optional(&mut *connection)
34                        .await
35                        .map_err(|error| {
36                            TrackError::new(
37                                ErrorCode::TaskWriteFailed,
38                                format!("Could not load backend setting `{key}`: {error}"),
39                            )
40                        })?;
41
42                row.map(|row| {
43                    serde_json::from_str::<T>(row.get::<String, _>("setting_json").as_str())
44                        .map_err(|error| {
45                            TrackError::new(
46                                ErrorCode::InvalidConfig,
47                                format!("Backend setting `{key}` is not valid JSON: {error}"),
48                            )
49                        })
50                })
51                .transpose()
52            })
53        })
54    }
55
56    pub fn save_json<T>(&self, key: &str, value: &T) -> Result<(), TrackError>
57    where
58        T: Serialize,
59    {
60        let key = key.to_owned();
61        let serialized = serde_json::to_string(value).map_err(|error| {
62            TrackError::new(
63                ErrorCode::InvalidConfig,
64                format!("Could not serialize backend setting `{key}`: {error}"),
65            )
66        })?;
67
68        self.database.run(move |connection| {
69            Box::pin(async move {
70                sqlx::query(
71                    r#"
72                    INSERT INTO backend_settings (setting_key, setting_json)
73                    VALUES (?1, ?2)
74                    ON CONFLICT(setting_key) DO UPDATE SET setting_json = excluded.setting_json
75                    "#,
76                )
77                .bind(&key)
78                .bind(&serialized)
79                .execute(&mut *connection)
80                .await
81                .map_err(|error| {
82                    TrackError::new(
83                        ErrorCode::TaskWriteFailed,
84                        format!("Could not save backend setting `{key}`: {error}"),
85                    )
86                })?;
87
88                Ok(())
89            })
90        })
91    }
92
93    pub fn delete(&self, key: &str) -> Result<(), TrackError> {
94        let key = key.to_owned();
95        self.database.run(move |connection| {
96            Box::pin(async move {
97                sqlx::query("DELETE FROM backend_settings WHERE setting_key = ?1")
98                    .bind(&key)
99                    .execute(&mut *connection)
100                    .await
101                    .map_err(|error| {
102                        TrackError::new(
103                            ErrorCode::TaskWriteFailed,
104                            format!("Could not delete backend setting `{key}`: {error}"),
105                        )
106                    })?;
107
108                Ok(())
109            })
110        })
111    }
112}