1use sqlx::Row;
2use sqlx::types::Uuid;
3use std::fmt::Debug;
4use supp_macro::command;
5
6use super::{CmdError, CmdResult};
7use crate::{
8 config::{ConfigError, ConfigOption},
9 db::get_connection,
10 user::User,
11};
12command! {
13 GetConfig {
14 #[required]
15 user_id: Uuid,
16 #[required]
17 name: String,
18 } => {
19 let user = User { id: user_id };
20 match user.config(&name).await {
25 Ok(opt) => Ok(opt.map(|v| match v {
26 ConfigOption::String(s) => CmdResult::String(s),
27 ConfigOption::Blob(b) => CmdResult::Data(b),
28 })),
29 Err(ConfigError::NoConfig(_)) => Ok(None),
30 Err(e) => Err(e.into()),
31 }
32 }
33}
34
35command! {
36 GetVersion {
37 } => {
38 const HASH: &str = env!("GIT_HASH");
39 Ok(Some(CmdResult::String(HASH.to_string())))
40 }
41}
42
43command! {
44 GetBuildDate {
45 } => {
46 const BUILD: &str = env!("BUILD_DATE");
47 Ok(Some(CmdResult::String(BUILD.to_string())))
48 }
49}
50
51command! {
52 SetConfig {
53 #[required]
54 user_id: Uuid,
55 #[required]
56 name: String,
57 #[required]
58 value: String,
59 } => {
60 let user = User { id: user_id };
61 user.set_config(&name, ConfigOption::String(value)).await?;
62 Ok(None)
63 }
64}
65
66command! {
67 SelectColumn {
68 #[required]
69 field: String,
70 #[required]
71 table: String,
72 } => {
73 let mut conn = get_connection().await.map_err(|err| {
74 log::error!("{}", t!("Database error: %{err}", err = err : {:?}));
75 ConfigError::DB
76 })?;
77
78 let values: Vec<String> = sqlx::query(sqlx::AssertSqlSafe(format!(
85 "SELECT {field}::text FROM {table}"
86 )))
87 .fetch_all(&mut *conn)
88 .await?
89 .into_iter()
90 .map(|row| row.get::<Option<String>, _>(0).unwrap_or_default())
91 .collect();
92
93 Ok(Some(CmdResult::Lines(values)))
94 }
95}
96
97#[cfg(test)]
98mod command_config_tests {
99 use super::*;
100 use crate::{db::DB_POOL, user::User};
101 use sqlx::{PgPool, types::Uuid};
102 use supp_macro::local_db_sqlx_test;
103 use tokio::sync::OnceCell;
104
105 static CONTEXT: OnceCell<()> = OnceCell::const_new();
107 static USER: OnceCell<User> = OnceCell::const_new();
108
109 async fn setup() {
110 CONTEXT
111 .get_or_init(|| async {
112 #[cfg(feature = "testlog")]
113 let _ = env_logger::builder()
114 .is_test(true)
115 .filter_level(log::LevelFilter::Trace)
116 .try_init();
117 })
118 .await;
119 USER.get_or_init(|| async { User { id: Uuid::new_v4() } })
120 .await;
121 }
122
123 #[local_db_sqlx_test]
124 async fn set_then_get_config_round_trips_per_user(pool: PgPool) -> anyhow::Result<()> {
125 let user_id = Uuid::new_v4();
126 SetConfig::new()
127 .user_id(user_id)
128 .name("testfield".to_string())
129 .value("testval".to_string())
130 .run()
131 .await?;
132
133 let val = GetConfig::new()
134 .user_id(user_id)
135 .name("testfield".to_string())
136 .run()
137 .await?
138 .unwrap();
139 assert_eq!(val.to_string(), "testval");
140 }
141}