Skip to main content

shared/models/
location_database_agent_host.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, Clone)]
12pub struct LocationDatabaseAgentHost {
13    pub location: Fetchable<super::location::Location>,
14    pub database_agent_host: super::database_agent_host::DatabaseAgentHost,
15
16    pub created: chrono::NaiveDateTime,
17
18    extension_data: super::ModelExtensionData,
19}
20
21impl BaseModel for LocationDatabaseAgentHost {
22    const NAME: &'static str = "location_database_agent_host";
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        let mut columns = BTreeMap::from([
40            (
41                "location_database_agent_hosts.location_uuid",
42                compact_str::format_compact!("{prefix}location_uuid"),
43            ),
44            (
45                "location_database_agent_hosts.created",
46                compact_str::format_compact!("{prefix}created"),
47            ),
48        ]);
49
50        columns.extend(super::database_agent_host::DatabaseAgentHost::base_columns(
51            Some("database_agent_host_"),
52        ));
53
54        columns
55    }
56
57    #[inline]
58    fn map(prefix: Option<&str>, row: &PgRow) -> Result<Self, crate::database::DatabaseError> {
59        let prefix = prefix.unwrap_or_default();
60
61        Ok(Self {
62            location: super::location::Location::get_fetchable(
63                row.try_get(compact_str::format_compact!("{prefix}location_uuid").as_str())?,
64            ),
65            database_agent_host: super::database_agent_host::DatabaseAgentHost::map(
66                Some("database_agent_host_"),
67                row,
68            )?,
69            created: row.try_get(compact_str::format_compact!("{prefix}created").as_str())?,
70            extension_data: Self::map_extensions(prefix, row)?,
71        })
72    }
73}
74
75impl LocationDatabaseAgentHost {
76    pub async fn by_location_uuid_database_agent_host_uuid(
77        database: &crate::database::Database,
78        location_uuid: uuid::Uuid,
79        database_agent_host_uuid: uuid::Uuid,
80    ) -> Result<Option<Self>, crate::database::DatabaseError> {
81        let row = sqlx::query(sqlx::AssertSqlSafe(format!(
82            r#"
83            SELECT {}
84            FROM location_database_agent_hosts
85            JOIN database_agent_hosts ON location_database_agent_hosts.database_agent_host_uuid = database_agent_hosts.uuid
86            WHERE location_database_agent_hosts.location_uuid = $1 AND location_database_agent_hosts.database_agent_host_uuid = $2
87            "#,
88            Self::columns_sql(None)
89        )))
90        .bind(location_uuid)
91        .bind(database_agent_host_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_location_uuid_database_agent_host_uuid_with_transaction(
99        transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
100        location_uuid: uuid::Uuid,
101        database_agent_host_uuid: uuid::Uuid,
102    ) -> Result<Option<Self>, crate::database::DatabaseError> {
103        let row = sqlx::query(sqlx::AssertSqlSafe(format!(
104            r#"
105            SELECT {}
106            FROM location_database_agent_hosts
107            JOIN database_agent_hosts ON location_database_agent_hosts.database_agent_host_uuid = database_agent_hosts.uuid
108            WHERE location_database_agent_hosts.location_uuid = $1 AND location_database_agent_hosts.database_agent_host_uuid = $2
109            "#,
110            Self::columns_sql(None)
111        )))
112        .bind(location_uuid)
113        .bind(database_agent_host_uuid)
114        .fetch_optional(&mut **transaction)
115        .await?;
116
117        row.try_map(|row| Self::map(None, &row))
118    }
119
120    pub async fn by_location_uuid_with_pagination(
121        database: &crate::database::Database,
122        location_uuid: uuid::Uuid,
123        page: i64,
124        per_page: i64,
125        search: Option<&str>,
126    ) -> Result<super::Pagination<Self>, crate::database::DatabaseError> {
127        let offset = (page - 1) * per_page;
128
129        let rows = sqlx::query(sqlx::AssertSqlSafe(format!(
130            r#"
131            SELECT {}, COUNT(*) OVER() AS total_count
132            FROM location_database_agent_hosts
133            JOIN database_agent_hosts ON location_database_agent_hosts.database_agent_host_uuid = database_agent_hosts.uuid
134            WHERE location_database_agent_hosts.location_uuid = $1 AND ($2 IS NULL OR database_agent_hosts.name ILIKE '%' || $2 || '%')
135            ORDER BY location_database_agent_hosts.created
136            LIMIT $3 OFFSET $4
137            "#,
138            Self::columns_sql(None)
139        )))
140        .bind(location_uuid)
141        .bind(search)
142        .bind(per_page)
143        .bind(offset)
144        .fetch_all(database.read())
145        .await?;
146
147        Ok(super::Pagination {
148            total: rows
149                .first()
150                .map_or(Ok(0), |row| row.try_get("total_count"))?,
151            per_page,
152            page,
153            data: rows
154                .into_iter()
155                .map(|row| Self::map(None, &row))
156                .try_collect_vec()?,
157        })
158    }
159}
160
161#[async_trait::async_trait]
162impl IntoAdminApiObject for LocationDatabaseAgentHost {
163    type AdminApiObject = AdminApiLocationDatabaseAgentHost;
164    type ExtraArgs<'a> = ();
165
166    async fn into_admin_api_object<'a>(
167        self,
168        state: &crate::State,
169        _args: Self::ExtraArgs<'a>,
170    ) -> Result<Self::AdminApiObject, crate::database::DatabaseError> {
171        let api_object = AdminApiLocationDatabaseAgentHost::init_hooks(&self, state).await?;
172
173        let api_object = finish_extendible!(
174            AdminApiLocationDatabaseAgentHost {
175                database_agent_host: self
176                    .database_agent_host
177                    .into_admin_api_object(state, ())
178                    .await?,
179                created: self.created.and_utc(),
180            },
181            api_object,
182            state
183        )?;
184
185        Ok(api_object)
186    }
187}
188
189#[derive(ToSchema, Deserialize, Validate)]
190pub struct CreateLocationDatabaseAgentHostOptions {
191    #[garde(skip)]
192    pub location_uuid: uuid::Uuid,
193    #[garde(skip)]
194    pub database_agent_host_uuid: uuid::Uuid,
195}
196
197#[async_trait::async_trait]
198impl CreatableModel for LocationDatabaseAgentHost {
199    type CreateOptions<'a> = CreateLocationDatabaseAgentHostOptions;
200    type CreateResult = Self;
201
202    fn get_create_handlers() -> &'static LazyLock<CreateListenerList<Self>> {
203        static CREATE_LISTENERS: LazyLock<CreateListenerList<LocationDatabaseAgentHost>> =
204            LazyLock::new(|| Arc::new(ModelHandlerList::default()));
205
206        &CREATE_LISTENERS
207    }
208
209    async fn create_with_transaction(
210        state: &crate::State,
211        mut options: Self::CreateOptions<'_>,
212        transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
213    ) -> Result<Self, crate::database::DatabaseError> {
214        options.validate()?;
215
216        super::database_agent_host::DatabaseAgentHost::by_uuid_optional_cached(
217            &state.database,
218            options.database_agent_host_uuid,
219        )
220        .await?
221        .ok_or(crate::database::InvalidRelationError("database_agent_host"))?;
222
223        let mut query_builder = InsertQueryBuilder::new("location_database_agent_hosts");
224
225        Self::run_create_handlers(&mut options, &mut query_builder, state, transaction).await?;
226
227        query_builder
228            .set("location_uuid", options.location_uuid)
229            .set("database_agent_host_uuid", options.database_agent_host_uuid);
230
231        query_builder.execute(&mut **transaction).await?;
232
233        let mut result = match Self::by_location_uuid_database_agent_host_uuid_with_transaction(
234            transaction,
235            options.location_uuid,
236            options.database_agent_host_uuid,
237        )
238        .await?
239        {
240            Some(location_database_agent_host) => location_database_agent_host,
241            None => return Err(sqlx::Error::RowNotFound.into()),
242        };
243
244        Self::run_after_create_handlers(&mut result, &options, state, transaction).await?;
245
246        Ok(result)
247    }
248}
249
250#[async_trait::async_trait]
251impl DeletableModel for LocationDatabaseAgentHost {
252    type DeleteOptions = ();
253
254    fn get_delete_handlers() -> &'static LazyLock<DeleteHandlerList<Self>> {
255        static DELETE_LISTENERS: LazyLock<DeleteHandlerList<LocationDatabaseAgentHost>> =
256            LazyLock::new(|| Arc::new(ModelHandlerList::default()));
257
258        &DELETE_LISTENERS
259    }
260
261    async fn delete_with_transaction(
262        &self,
263        state: &crate::State,
264        options: Self::DeleteOptions,
265        transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
266    ) -> Result<(), anyhow::Error> {
267        self.run_delete_handlers(&options, state, transaction)
268            .await?;
269
270        sqlx::query(
271            r#"
272            DELETE FROM location_database_agent_hosts
273            WHERE location_database_agent_hosts.location_uuid = $1 AND location_database_agent_hosts.database_agent_host_uuid = $2
274            "#,
275        )
276        .bind(self.location.uuid)
277        .bind(self.database_agent_host.uuid)
278        .execute(&mut **transaction)
279        .await?;
280
281        self.run_after_delete_handlers(&options, state, transaction)
282            .await?;
283
284        Ok(())
285    }
286}
287
288#[schema_extension_derive::extendible]
289#[init_args(LocationDatabaseAgentHost, crate::State)]
290#[hook_args(crate::State)]
291#[derive(ToSchema, Serialize)]
292#[schema(title = "LocationDatabaseAgentHost")]
293pub struct AdminApiLocationDatabaseAgentHost {
294    pub database_agent_host: super::database_agent_host::AdminApiDatabaseAgentHost,
295
296    pub created: chrono::DateTime<chrono::Utc>,
297}