Skip to main content

shared/models/
system_backup_policy_location.rs

1use crate::{models::InsertQueryBuilder, prelude::*};
2use garde::Validate;
3use serde::{Deserialize, Serialize};
4use sqlx::{Row, postgres::PgRow};
5use std::{
6    collections::BTreeMap,
7    sync::{Arc, LazyLock},
8};
9use utoipa::ToSchema;
10
11#[derive(Serialize, Deserialize)]
12pub struct SystemBackupPolicyLocation {
13    pub system_backup_policy: Fetchable<super::system_backup_policy::SystemBackupPolicy>,
14    pub location: Fetchable<super::location::Location>,
15
16    pub created: chrono::NaiveDateTime,
17
18    extension_data: super::ModelExtensionData,
19}
20
21impl BaseModel for SystemBackupPolicyLocation {
22    const NAME: &'static str = "system_backup_policy_location";
23
24    fn get_extension_list() -> &'static super::ModelExtensionList {
25        static EXTENSIONS: LazyLock<super::ModelExtensionList> =
26            LazyLock::new(|| parking_lot::RwLock::new(Vec::new()));
27
28        &EXTENSIONS
29    }
30
31    fn get_extension_data(&self) -> &super::ModelExtensionData {
32        &self.extension_data
33    }
34
35    #[inline]
36    fn base_columns(prefix: Option<&str>) -> BTreeMap<&'static str, compact_str::CompactString> {
37        let prefix = prefix.unwrap_or_default();
38
39        BTreeMap::from([
40            (
41                "system_backup_policy_locations.system_backup_policy_uuid",
42                compact_str::format_compact!("{prefix}system_backup_policy_uuid"),
43            ),
44            (
45                "system_backup_policy_locations.location_uuid",
46                compact_str::format_compact!("{prefix}location_uuid"),
47            ),
48            (
49                "system_backup_policy_locations.created",
50                compact_str::format_compact!("{prefix}created"),
51            ),
52        ])
53    }
54
55    #[inline]
56    fn map(prefix: Option<&str>, row: &PgRow) -> Result<Self, crate::database::DatabaseError> {
57        let prefix = prefix.unwrap_or_default();
58
59        Ok(Self {
60            system_backup_policy: super::system_backup_policy::SystemBackupPolicy::get_fetchable(
61                row.try_get(
62                    compact_str::format_compact!("{prefix}system_backup_policy_uuid").as_str(),
63                )?,
64            ),
65            location: super::location::Location::get_fetchable(
66                row.try_get(compact_str::format_compact!("{prefix}location_uuid").as_str())?,
67            ),
68            created: row.try_get(compact_str::format_compact!("{prefix}created").as_str())?,
69            extension_data: Self::map_extensions(prefix, row)?,
70        })
71    }
72}
73
74impl SystemBackupPolicyLocation {
75    pub async fn by_system_backup_policy_uuid_location_uuid(
76        database: &crate::database::Database,
77        system_backup_policy_uuid: uuid::Uuid,
78        location_uuid: uuid::Uuid,
79    ) -> Result<Option<Self>, crate::database::DatabaseError> {
80        let row = sqlx::query(sqlx::AssertSqlSafe(format!(
81            r#"
82            SELECT {}
83            FROM system_backup_policy_locations
84            WHERE
85                system_backup_policy_locations.system_backup_policy_uuid = $1
86                AND system_backup_policy_locations.location_uuid = $2
87            "#,
88            Self::columns_sql(None)
89        )))
90        .bind(system_backup_policy_uuid)
91        .bind(location_uuid)
92        .fetch_optional(database.read())
93        .await?;
94
95        row.try_map(|row| Self::map(None, &row))
96    }
97
98    pub async fn by_system_backup_policy_uuid_with_pagination(
99        database: &crate::database::Database,
100        system_backup_policy_uuid: uuid::Uuid,
101        page: i64,
102        per_page: i64,
103        search: Option<&str>,
104    ) -> Result<super::Pagination<Self>, crate::database::DatabaseError> {
105        let offset = (page - 1) * per_page;
106
107        let rows = sqlx::query(sqlx::AssertSqlSafe(format!(
108            r#"
109            SELECT {}, COUNT(*) OVER() AS total_count
110            FROM system_backup_policy_locations
111            JOIN locations ON locations.uuid = system_backup_policy_locations.location_uuid
112            WHERE
113                system_backup_policy_locations.system_backup_policy_uuid = $1
114                AND ($2 IS NULL OR locations.name ILIKE '%' || $2 || '%')
115            ORDER BY system_backup_policy_locations.created
116            LIMIT $3 OFFSET $4
117            "#,
118            Self::columns_sql(None)
119        )))
120        .bind(system_backup_policy_uuid)
121        .bind(search)
122        .bind(per_page)
123        .bind(offset)
124        .fetch_all(database.read())
125        .await?;
126
127        Ok(super::Pagination {
128            total: rows
129                .first()
130                .map_or(Ok(0), |row| row.try_get("total_count"))?,
131            per_page,
132            page,
133            data: rows
134                .into_iter()
135                .map(|row| Self::map(None, &row))
136                .try_collect_vec()?,
137        })
138    }
139}
140
141#[async_trait::async_trait]
142impl IntoAdminApiObject for SystemBackupPolicyLocation {
143    type AdminApiObject = AdminApiSystemBackupPolicyLocation;
144    type ExtraArgs<'a> = ();
145
146    async fn into_admin_api_object<'a>(
147        self,
148        state: &crate::State,
149        _args: Self::ExtraArgs<'a>,
150    ) -> Result<Self::AdminApiObject, crate::database::DatabaseError> {
151        let api_object = AdminApiSystemBackupPolicyLocation::init_hooks(&self, state).await?;
152
153        let api_object = finish_extendible!(
154            AdminApiSystemBackupPolicyLocation {
155                location: self
156                    .location
157                    .fetch_cached(&state.database)
158                    .await?
159                    .into_admin_api_object(state, ())
160                    .await?,
161                created: self.created.and_utc(),
162            },
163            api_object,
164            state
165        )?;
166
167        Ok(api_object)
168    }
169}
170
171#[derive(ToSchema, Deserialize, Validate)]
172pub struct CreateSystemBackupPolicyLocationOptions {
173    #[garde(skip)]
174    pub system_backup_policy_uuid: uuid::Uuid,
175    #[garde(skip)]
176    pub location_uuid: uuid::Uuid,
177}
178
179#[async_trait::async_trait]
180impl CreatableModel for SystemBackupPolicyLocation {
181    type CreateOptions<'a> = CreateSystemBackupPolicyLocationOptions;
182    type CreateResult = Self;
183
184    fn get_create_handlers() -> &'static LazyLock<CreateListenerList<Self>> {
185        static CREATE_LISTENERS: LazyLock<CreateListenerList<SystemBackupPolicyLocation>> =
186            LazyLock::new(|| Arc::new(ModelHandlerList::default()));
187
188        &CREATE_LISTENERS
189    }
190
191    async fn create_with_transaction(
192        state: &crate::State,
193        mut options: Self::CreateOptions<'_>,
194        transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
195    ) -> Result<Self, crate::database::DatabaseError> {
196        options.validate()?;
197
198        super::location::Location::by_uuid_optional_cached(&state.database, options.location_uuid)
199            .await?
200            .ok_or(crate::database::InvalidRelationError("location"))?;
201
202        let mut query_builder = InsertQueryBuilder::new("system_backup_policy_locations");
203
204        Self::run_create_handlers(&mut options, &mut query_builder, state, transaction).await?;
205
206        query_builder
207            .set(
208                "system_backup_policy_uuid",
209                options.system_backup_policy_uuid,
210            )
211            .set("location_uuid", options.location_uuid);
212
213        let row = query_builder
214            .returning(&Self::columns_sql(None))
215            .fetch_one(&mut **transaction)
216            .await?;
217        let mut policy_location = Self::map(None, &row)?;
218
219        Self::run_after_create_handlers(&mut policy_location, &options, state, transaction).await?;
220
221        Ok(policy_location)
222    }
223}
224
225#[async_trait::async_trait]
226impl DeletableModel for SystemBackupPolicyLocation {
227    type DeleteOptions = ();
228
229    fn get_delete_handlers() -> &'static LazyLock<DeleteHandlerList<Self>> {
230        static DELETE_LISTENERS: LazyLock<DeleteHandlerList<SystemBackupPolicyLocation>> =
231            LazyLock::new(|| Arc::new(ModelHandlerList::default()));
232
233        &DELETE_LISTENERS
234    }
235
236    async fn delete_with_transaction(
237        &self,
238        state: &crate::State,
239        options: Self::DeleteOptions,
240        transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
241    ) -> Result<(), anyhow::Error> {
242        self.run_delete_handlers(&options, state, transaction)
243            .await?;
244
245        sqlx::query(
246            r#"
247            DELETE FROM system_backup_policy_locations
248            WHERE
249                system_backup_policy_locations.system_backup_policy_uuid = $1
250                AND system_backup_policy_locations.location_uuid = $2
251            "#,
252        )
253        .bind(self.system_backup_policy.uuid)
254        .bind(self.location.uuid)
255        .execute(&mut **transaction)
256        .await?;
257
258        self.run_after_delete_handlers(&options, state, transaction)
259            .await?;
260
261        Ok(())
262    }
263}
264
265#[schema_extension_derive::extendible]
266#[init_args(SystemBackupPolicyLocation, crate::State)]
267#[hook_args(crate::State)]
268#[derive(ToSchema, Serialize)]
269#[schema(title = "SystemBackupPolicyLocation")]
270pub struct AdminApiSystemBackupPolicyLocation {
271    pub location: super::location::AdminApiLocation,
272
273    pub created: chrono::DateTime<chrono::Utc>,
274}