use anyhow::Error; use futures_util::StreamExt; use giterated_models::model::{repository::Repository, user::User}; use serde_json::Value; use sqlx::{Either, PgPool}; use super::SettingsBackend; pub struct DatabaseSettings { pub pg_pool: PgPool, } #[async_trait::async_trait] impl SettingsBackend for DatabaseSettings { async fn user_get(&mut self, user: &User) -> Result, Error> { let settings = sqlx::query_as!( UserSettingRow, r#"SELECT * FROM user_settings WHERE username = $1"#, user.username ) .fetch_many(&self.pg_pool) .filter_map(|result| async move { if let Ok(Either::Right(row)) = result { Some(row) } else { None } }) .filter_map(|row| async move { if let Ok(value) = serde_json::from_str(&row.value) { Some((row.name, value)) } else { None } }) .collect::>() .await; Ok(settings) } async fn user_write( &mut self, user: &User, settings: &[(String, String)], ) -> Result<(), Error> { for (name, value) in settings { sqlx::query!("INSERT INTO user_settings VALUES ($1, $2, $3) ON CONFLICT (username, name) DO UPDATE SET value = $3", user.username, name, value) .execute(&self.pg_pool).await?; } Ok(()) } async fn repository_get( &mut self, repository: &Repository, ) -> Result, Error> { let settings = sqlx::query_as!( RepositorySettingRow, r#"SELECT * FROM repository_settings WHERE repository = $1"#, repository.to_string() ) .fetch_many(&self.pg_pool) .filter_map(|result| async move { if let Ok(Either::Right(row)) = result { Some(row) } else { None } }) .filter_map(|row| async move { if let Ok(value) = serde_json::from_str(&row.value) { Some((row.name, value)) } else { None } }) .collect::>() .await; Ok(settings) } async fn repository_write( &mut self, repository: &Repository, settings: &[(String, String)], ) -> Result<(), Error> { for (name, value) in settings { sqlx::query!("INSERT INTO repository_settings VALUES ($1, $2, $3) ON CONFLICT (repository, name) DO UPDATE SET value = $3", repository.to_string(), name, value) .execute(&self.pg_pool).await?; } Ok(()) } } #[allow(unused)] #[derive(Debug, sqlx::FromRow)] struct UserSettingRow { pub username: String, pub name: String, pub value: String, } #[allow(unused)] #[derive(Debug, sqlx::FromRow)] struct RepositorySettingRow { pub repository: String, pub name: String, pub value: String, }