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 super::PaginatedQueryBuilder::new(
128 Self::columns_sql(None),
129 format!(
130 r#"
131 FROM location_database_agent_hosts
132 JOIN database_agent_hosts ON location_database_agent_hosts.database_agent_host_uuid = database_agent_hosts.uuid
133 WHERE location_database_agent_hosts.location_uuid = $1 AND {search}
134 "#,
135 search = super::search_sql(2, &["database_agent_hosts.name"], &["database_agent_hosts.uuid"]),
136 ),
137 "location_database_agent_hosts.created, location_database_agent_hosts.location_uuid, location_database_agent_hosts.database_agent_host_uuid",
138 )
139 .bind(location_uuid)
140 .bind(search)
141 .fetch(database, page, per_page)
142 .await
143 }
144}
145
146#[async_trait::async_trait]
147impl IntoAdminApiObject for LocationDatabaseAgentHost {
148 type AdminApiObject = AdminApiLocationDatabaseAgentHost;
149 type ExtraArgs<'a> = ();
150
151 async fn into_admin_api_object<'a>(
152 self,
153 state: &crate::State,
154 _args: Self::ExtraArgs<'a>,
155 ) -> Result<Self::AdminApiObject, crate::database::DatabaseError> {
156 let api_object = AdminApiLocationDatabaseAgentHost::init_hooks(&self, state).await?;
157
158 let api_object = finish_extendible!(
159 AdminApiLocationDatabaseAgentHost {
160 database_agent_host: self
161 .database_agent_host
162 .into_admin_api_object(state, ())
163 .await?,
164 created: self.created.and_utc(),
165 },
166 api_object,
167 state
168 )?;
169
170 Ok(api_object)
171 }
172}
173
174#[derive(ToSchema, Deserialize, Validate)]
175pub struct CreateLocationDatabaseAgentHostOptions {
176 #[garde(skip)]
177 pub location_uuid: uuid::Uuid,
178 #[garde(skip)]
179 pub database_agent_host_uuid: uuid::Uuid,
180}
181
182#[async_trait::async_trait]
183impl CreatableModel for LocationDatabaseAgentHost {
184 type CreateOptions<'a> = CreateLocationDatabaseAgentHostOptions;
185 type CreateResult = Self;
186
187 fn get_create_handlers() -> &'static LazyLock<CreateListenerList<Self>> {
188 static CREATE_LISTENERS: LazyLock<CreateListenerList<LocationDatabaseAgentHost>> =
189 LazyLock::new(|| Arc::new(ModelHandlerList::default()));
190
191 &CREATE_LISTENERS
192 }
193
194 async fn create_with_transaction(
195 state: &crate::State,
196 mut options: Self::CreateOptions<'_>,
197 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
198 ) -> Result<Self, crate::database::DatabaseError> {
199 options.validate()?;
200
201 super::database_agent_host::DatabaseAgentHost::by_uuid_optional_cached(
202 &state.database,
203 options.database_agent_host_uuid,
204 )
205 .await?
206 .ok_or(crate::database::InvalidRelationError("database_agent_host"))?;
207
208 let mut query_builder = InsertQueryBuilder::new("location_database_agent_hosts");
209
210 Self::run_create_handlers(&mut options, &mut query_builder, state, transaction).await?;
211
212 query_builder
213 .set("location_uuid", options.location_uuid)
214 .set("database_agent_host_uuid", options.database_agent_host_uuid);
215
216 query_builder.execute(&mut **transaction).await?;
217
218 let mut result = match Self::by_location_uuid_database_agent_host_uuid_with_transaction(
219 transaction,
220 options.location_uuid,
221 options.database_agent_host_uuid,
222 )
223 .await?
224 {
225 Some(location_database_agent_host) => location_database_agent_host,
226 None => return Err(sqlx::Error::RowNotFound.into()),
227 };
228
229 Self::run_after_create_handlers(&mut result, &options, state, transaction).await?;
230
231 Ok(result)
232 }
233}
234
235#[async_trait::async_trait]
236impl DeletableModel for LocationDatabaseAgentHost {
237 type DeleteOptions = ();
238
239 fn get_delete_handlers() -> &'static LazyLock<DeleteHandlerList<Self>> {
240 static DELETE_LISTENERS: LazyLock<DeleteHandlerList<LocationDatabaseAgentHost>> =
241 LazyLock::new(|| Arc::new(ModelHandlerList::default()));
242
243 &DELETE_LISTENERS
244 }
245
246 async fn delete_with_transaction(
247 &self,
248 state: &crate::State,
249 options: Self::DeleteOptions,
250 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
251 ) -> Result<(), anyhow::Error> {
252 self.run_delete_handlers(&options, state, transaction)
253 .await?;
254
255 sqlx::query(
256 r#"
257 DELETE FROM location_database_agent_hosts
258 WHERE location_database_agent_hosts.location_uuid = $1 AND location_database_agent_hosts.database_agent_host_uuid = $2
259 "#,
260 )
261 .bind(self.location.uuid)
262 .bind(self.database_agent_host.uuid)
263 .execute(&mut **transaction)
264 .await?;
265
266 self.run_after_delete_handlers(&options, state, transaction)
267 .await?;
268
269 Ok(())
270 }
271}
272
273#[schema_extension_derive::extendible]
274#[init_args(LocationDatabaseAgentHost, crate::State)]
275#[hook_args(crate::State)]
276#[derive(ToSchema, Serialize)]
277#[schema(title = "LocationDatabaseAgentHost")]
278pub struct AdminApiLocationDatabaseAgentHost {
279 pub database_agent_host: super::database_agent_host::AdminApiDatabaseAgentHost,
280
281 pub created: chrono::DateTime<chrono::Utc>,
282}