shared/models/
server_variable.rs1use crate::prelude::*;
2use serde::{Deserialize, Serialize};
3use sqlx::{Row, postgres::PgRow};
4use std::{collections::BTreeMap, sync::LazyLock};
5#[derive(Serialize, Deserialize)]
6pub struct ServerVariable {
7 pub variable: super::nest_egg_variable::NestEggVariable,
8
9 pub value: String,
10
11 pub created: chrono::NaiveDateTime,
12
13 extension_data: super::ModelExtensionData,
14}
15
16impl BaseModel for ServerVariable {
17 const NAME: &'static str = "server_variable";
18
19 fn get_extension_list() -> &'static super::ModelExtensionList {
20 static EXTENSIONS: LazyLock<super::ModelExtensionList> =
21 LazyLock::new(|| std::sync::RwLock::new(Vec::new()));
22
23 &EXTENSIONS
24 }
25
26 fn get_extension_data(&self) -> &super::ModelExtensionData {
27 &self.extension_data
28 }
29
30 #[inline]
31 fn base_columns(prefix: Option<&str>) -> BTreeMap<&'static str, compact_str::CompactString> {
32 let prefix = prefix.unwrap_or_default();
33
34 let mut columns = BTreeMap::from([
35 (
36 "server_variables.value",
37 compact_str::format_compact!("{prefix}value"),
38 ),
39 (
40 "server_variables.created",
41 compact_str::format_compact!("{prefix}created"),
42 ),
43 ]);
44
45 columns.extend(super::nest_egg_variable::NestEggVariable::base_columns(
46 Some("variable_"),
47 ));
48
49 columns
50 }
51
52 #[inline]
53 fn map(prefix: Option<&str>, row: &PgRow) -> Result<Self, crate::database::DatabaseError> {
54 let prefix = prefix.unwrap_or_default();
55
56 let variable = super::nest_egg_variable::NestEggVariable::map(Some("variable_"), row)?;
57 let value = row
58 .try_get(compact_str::format_compact!("{prefix}value").as_str())
59 .unwrap_or_else(|_| {
60 variable
61 .default_value
62 .clone()
63 .unwrap_or_else(|| "".to_string())
64 });
65
66 Ok(Self {
67 variable,
68 value,
69 created: row
70 .try_get(compact_str::format_compact!("{prefix}created").as_str())
71 .unwrap_or_else(|_| chrono::Utc::now().naive_utc()),
72 extension_data: Self::map_extensions(prefix, row)?,
73 })
74 }
75}
76
77impl ServerVariable {
78 pub async fn create(
79 database: &crate::database::Database,
80 server_uuid: uuid::Uuid,
81 variable_uuid: uuid::Uuid,
82 value: &str,
83 ) -> Result<(), crate::database::DatabaseError> {
84 sqlx::query(
85 r#"
86 INSERT INTO server_variables (server_uuid, variable_uuid, value)
87 VALUES ($1, $2, $3)
88 ON CONFLICT (server_uuid, variable_uuid) DO UPDATE SET value = EXCLUDED.value
89 "#,
90 )
91 .bind(server_uuid)
92 .bind(variable_uuid)
93 .bind(value)
94 .execute(database.write())
95 .await?;
96
97 Ok(())
98 }
99
100 pub async fn all_by_server_uuid_egg_uuid(
101 database: &crate::database::Database,
102 server_uuid: uuid::Uuid,
103 egg_uuid: uuid::Uuid,
104 ) -> Result<Vec<Self>, crate::database::DatabaseError> {
105 let rows = sqlx::query(&format!(
106 r#"
107 SELECT {}
108 FROM nest_egg_variables
109 LEFT JOIN server_variables ON server_variables.variable_uuid = nest_egg_variables.uuid AND server_variables.server_uuid = $1
110 WHERE nest_egg_variables.egg_uuid = $2
111 ORDER BY nest_egg_variables.order_, nest_egg_variables.created
112 "#,
113 Self::columns_sql(None)
114 ))
115 .bind(server_uuid)
116 .bind(egg_uuid)
117 .fetch_all(database.read())
118 .await?;
119
120 rows.into_iter()
121 .map(|row| Self::map(None, &row))
122 .try_collect_vec()
123 }
124}
125
126#[async_trait::async_trait]
127impl IntoApiObject for ServerVariable {
128 type ApiObject = ApiServerVariable;
129 type ExtraArgs<'a> = ();
130
131 async fn into_api_object<'a>(
132 self,
133 state: &crate::State,
134 _args: Self::ExtraArgs<'a>,
135 ) -> Result<Self::ApiObject, crate::database::DatabaseError> {
136 let api_object = ApiServerVariable::init_hooks(&self, state).await?;
137
138 let api_object = finish_extendible!(
139 ApiServerVariable {
140 name: self.variable.name,
141 name_translations: self.variable.name_translations,
142 description: self.variable.description,
143 description_translations: self.variable.description_translations,
144 env_variable: self.variable.env_variable,
145 default_value: self.variable.default_value,
146 value: self.value,
147 is_editable: self.variable.user_editable,
148 is_secret: self.variable.secret,
149 rules: self.variable.rules,
150 created: self.created.and_utc(),
151 },
152 api_object,
153 state
154 )?;
155
156 Ok(api_object)
157 }
158}
159
160#[schema_extension_derive::extendible]
161#[init_args(ServerVariable, crate::State)]
162#[hook_args(crate::State)]
163#[derive(ToSchema, Serialize)]
164#[schema(title = "ServerVariable")]
165pub struct ApiServerVariable {
166 pub name: compact_str::CompactString,
167 pub name_translations: BTreeMap<compact_str::CompactString, compact_str::CompactString>,
168 pub description: Option<compact_str::CompactString>,
169 pub description_translations: BTreeMap<compact_str::CompactString, compact_str::CompactString>,
170
171 pub env_variable: compact_str::CompactString,
172 pub default_value: Option<String>,
173 pub value: String,
174 pub is_editable: bool,
175 pub is_secret: bool,
176 pub rules: Vec<compact_str::CompactString>,
177
178 pub created: chrono::DateTime<chrono::Utc>,
179}