Skip to main content

shared/models/
server_variable.rs

1use 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}