1use crate::{database::DatabaseError, prelude::IteratorExt};
2use compact_str::CompactStringExt;
3use futures_util::{StreamExt, TryStreamExt};
4use garde::Validate;
5use parking_lot::RwLock;
6use serde::{Deserialize, Serialize, de::DeserializeOwned};
7use sha2::Digest;
8use sqlx::{
9 Arguments, Postgres, QueryBuilder, Row,
10 encode::IsNull,
11 error::BoxDynError,
12 postgres::{PgArgumentBuffer, PgArguments, PgRow, PgTypeInfo},
13};
14use std::{
15 collections::{BTreeMap, HashSet},
16 marker::PhantomData,
17 pin::Pin,
18 sync::{Arc, LazyLock},
19};
20use utoipa::ToSchema;
21
22pub mod admin_activity;
23pub mod announcement;
24pub mod backup_configuration;
25pub mod database_agent_host;
26pub mod database_agent_template;
27pub mod database_host;
28pub mod device;
29pub mod egg_configuration;
30pub mod egg_repository;
31pub mod egg_repository_egg;
32pub mod location;
33pub mod location_database_agent_host;
34pub mod location_database_host;
35pub mod mount;
36pub mod nest;
37pub mod nest_egg;
38pub mod nest_egg_device;
39pub mod nest_egg_mount;
40pub mod nest_egg_variable;
41pub mod node;
42pub mod node_allocation;
43pub mod node_database_agent_host;
44pub mod node_database_host;
45pub mod node_device;
46pub mod node_mount;
47pub mod node_tunnel;
48pub mod oauth_provider;
49pub mod oauth_provider_mapping;
50pub mod role;
51pub mod server;
52pub mod server_activity;
53pub mod server_allocation;
54pub mod server_backup;
55pub mod server_backup_group;
56pub mod server_database;
57pub mod server_database_instance;
58pub mod server_device;
59pub mod server_mount;
60pub mod server_schedule;
61pub mod server_schedule_step;
62pub mod server_subuser;
63pub mod server_tunnel;
64pub mod server_variable;
65pub mod system_backup_policy;
66pub mod system_backup_policy_database_agent_host;
67pub mod system_backup_policy_location;
68pub mod system_backup_policy_node;
69pub mod system_backup_policy_server;
70pub mod user;
71pub mod user_activity;
72pub mod user_api_key;
73pub mod user_command_snippet;
74pub mod user_email_verification;
75pub mod user_oauth_link;
76pub mod user_password_reset;
77pub mod user_recovery_code;
78pub mod user_security_key;
79pub mod user_server_group;
80pub mod user_session;
81pub mod user_ssh_key;
82pub mod user_two_factor_code;
83
84#[derive(ToSchema, Validate, Deserialize, Serialize)]
85pub struct PaginationParams {
86 #[garde(range(min = 1))]
87 #[schema(minimum = 1)]
88 #[serde(default = "Pagination::default_page")]
89 pub page: i64,
90 #[garde(range(min = 1, max = 100))]
91 #[schema(minimum = 1, maximum = 100)]
92 #[serde(default = "Pagination::default_per_page")]
93 pub per_page: i64,
94}
95
96#[derive(ToSchema, Validate, Deserialize, Serialize)]
97pub struct PaginationParamsWithSearch {
98 #[garde(range(min = 1))]
99 #[schema(minimum = 1)]
100 #[serde(default = "Pagination::default_page")]
101 pub page: i64,
102 #[garde(range(min = 1, max = 100))]
103 #[schema(minimum = 1, maximum = 100)]
104 #[serde(default = "Pagination::default_per_page")]
105 pub per_page: i64,
106 #[garde(length(chars, min = 1, max = 128))]
107 #[schema(min_length = 1, max_length = 128)]
108 #[serde(
109 default,
110 deserialize_with = "crate::deserialize::deserialize_search_option"
111 )]
112 pub search: Option<compact_str::CompactString>,
113}
114
115#[derive(ToSchema, Deserialize, Serialize)]
116pub struct Pagination<T: Serialize = serde_json::Value> {
117 pub total: i64,
118 pub per_page: i64,
119 pub page: i64,
120
121 pub data: Vec<T>,
122}
123
124impl Pagination {
125 #[inline]
126 pub const fn default_page() -> i64 {
127 1
128 }
129
130 #[inline]
131 pub const fn default_per_page() -> i64 {
132 25
133 }
134}
135
136impl<T: Serialize> Pagination<T> {
137 pub async fn async_map<R: serde::Serialize, Fut: Future<Output = R>>(
138 self,
139 mapper: impl Fn(T) -> Fut,
140 ) -> Pagination<R> {
141 let mut results = Vec::new();
142 results.reserve_exact(self.data.len());
143 let mut result_stream =
144 futures_util::stream::iter(self.data.into_iter().map(mapper)).buffered(25);
145
146 while let Some(result) = result_stream.next().await {
147 results.push(result);
148 }
149
150 Pagination {
151 total: self.total,
152 per_page: self.per_page,
153 page: self.page,
154 data: results,
155 }
156 }
157
158 pub async fn try_async_map<R: serde::Serialize, E, Fut: Future<Output = Result<R, E>>>(
159 self,
160 mapper: impl Fn(T) -> Fut,
161 ) -> Result<Pagination<R>, E> {
162 let mut results = Vec::new();
163 results.reserve_exact(self.data.len());
164 let mut result_stream =
165 futures_util::stream::iter(self.data.into_iter().map(mapper)).buffered(25);
166
167 while let Some(result) = result_stream.try_next().await? {
168 results.push(result);
169 }
170
171 Ok(Pagination {
172 total: self.total,
173 per_page: self.per_page,
174 page: self.page,
175 data: results,
176 })
177 }
178}
179
180pub fn search_sql(
186 param: u8,
187 text_columns: &[&str],
188 uuid_columns: &[&str],
189) -> compact_str::CompactString {
190 let mut clauses = Vec::with_capacity(text_columns.len() + uuid_columns.len() + 1);
191 clauses.push(compact_str::format_compact!("${param}::text IS NULL"));
192
193 for column in text_columns {
194 clauses.push(compact_str::format_compact!(
195 "{column} ILIKE '%' || ${param} || '%'"
196 ));
197 }
198
199 for column in uuid_columns {
200 clauses.push(uuid_search_sql(param, column));
201 }
202
203 compact_str::format_compact!("({})", clauses.join_compact(" OR "))
204}
205
206pub fn uuid_search_sql(param: u8, column: &str) -> compact_str::CompactString {
209 compact_str::format_compact!(
210 "(length(${param}) >= 8 AND {column}::text LIKE lower(${param}) || '%')"
211 )
212}
213
214pub type ModelExtensionList = parking_lot::RwLock<Vec<Box<dyn ModelExtension + Send + Sync>>>;
215pub type ModelExtensionData = Vec<(compact_str::CompactString, Vec<u8>)>;
216pub type ModelExtensionMapType = Box<dyn erased_serde::Serialize>;
217
218pub trait ModelExtension {
219 fn extension_name(&self) -> &'static str;
220
221 fn extended_columns(&self, prefix: &str) -> BTreeMap<&'static str, compact_str::CompactString>;
222
223 fn map_extended(
224 &self,
225 prefix: &str,
226 row: &PgRow,
227 ) -> Result<ModelExtensionMapType, crate::database::DatabaseError>;
228}
229
230pub trait SafeModelExtension: ModelExtension {
231 type Value: Serialize + DeserializeOwned;
232
233 fn name() -> &'static str;
234}
235
236pub trait BaseModel: Serialize + DeserializeOwned {
237 const NAME: &'static str;
238
239 fn get_extension_list() -> &'static ModelExtensionList;
240 fn get_extension_data(&self) -> &ModelExtensionData;
241
242 fn register_model_extension(extension: impl ModelExtension + Send + Sync + 'static) {
244 let mut extensions = Self::get_extension_list().write();
245
246 if extensions
247 .iter()
248 .any(|e| e.extension_name() == extension.extension_name())
249 {
250 return;
251 }
252
253 extensions.push(Box::new(extension));
254 }
255
256 fn parse_model_extension<Extension: SafeModelExtension>(
260 &self,
261 ) -> Result<Extension::Value, crate::database::DatabaseError>
262 where
263 Extension::Value: Serialize + DeserializeOwned,
264 {
265 let data = self.get_extension_data();
266
267 for (name, value) in data.iter() {
268 if name.as_str() == Extension::name() {
269 let deserialized =
270 rmp_serde::from_slice::<Extension::Value>(value).map_err(anyhow::Error::new)?;
271
272 return Ok(deserialized);
273 }
274 }
275
276 Err(crate::database::DatabaseError::Any(anyhow::anyhow!(
277 "model extension not found"
278 )))
279 }
280
281 fn base_columns(prefix: Option<&str>) -> BTreeMap<&'static str, compact_str::CompactString>;
282 fn columns(prefix: Option<&str>) -> BTreeMap<&'static str, compact_str::CompactString> {
283 let extensions = Self::get_extension_list().read();
284
285 let mut columns = Self::base_columns(prefix);
286
287 for extension in extensions.iter() {
288 columns.extend(extension.extended_columns(prefix.unwrap_or_default()));
289 }
290
291 columns
292 }
293
294 #[inline]
295 fn columns_sql(prefix: Option<&str>) -> compact_str::CompactString {
296 Self::columns(prefix)
297 .iter()
298 .map(|(key, value)| compact_str::format_compact!("{key} as {value}"))
299 .join_compact(", ")
300 }
301
302 fn map_extensions(
303 prefix: &str,
304 row: &PgRow,
305 ) -> Result<ModelExtensionData, crate::database::DatabaseError> {
306 let mut data = Vec::new();
307
308 let extensions = Self::get_extension_list().read();
309 for extension in extensions.iter() {
310 let value = extension.map_extended(prefix, row)?;
311 let serialized = rmp_serde::to_vec(&value).map_err(anyhow::Error::new)?;
312
313 data.push((
314 compact_str::CompactString::const_new(extension.extension_name()),
315 serialized,
316 ));
317 }
318
319 Ok(data)
320 }
321
322 fn map(prefix: Option<&str>, row: &PgRow) -> Result<Self, crate::database::DatabaseError>;
323
324 fn cache_invalidation_keys(&self) -> Vec<compact_str::CompactString> {
325 Vec::new()
326 }
327}
328
329pub async fn invalidate_cache_keys(
330 database: &crate::database::Database,
331 keys: &[compact_str::CompactString],
332) {
333 for key in keys {
334 if let Err(err) = database.cache.invalidate(key).await {
335 tracing::warn!(key = %key, "failed to invalidate cache entry: {err:#?}");
336 }
337 }
338}
339
340pub trait EventEmittingModel: BaseModel {
341 type Event: Send + Sync + 'static;
342
343 fn get_event_emitter() -> &'static crate::events::EventEmitter<Self::Event>;
344
345 fn register_event_handler<
346 F: Fn(crate::State, Arc<Self::Event>) -> Fut + Send + Sync + 'static,
347 Fut: Future<Output = Result<(), anyhow::Error>> + Send + 'static,
348 >(
349 listener: F,
350 ) -> crate::events::EventHandlerHandle {
351 Self::get_event_emitter().register_event_handler(listener)
352 }
353}
354
355type CreateHandlerResult<'a> =
356 Pin<Box<dyn Future<Output = Result<(), crate::database::DatabaseError>> + Send + 'a>>;
357type CreateHandler<M> = dyn for<'a> Fn(
358 &'a mut <M as CreatableModel>::CreateOptions<'_>,
359 &'a mut InsertQueryBuilder,
360 &'a crate::State,
361 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
362 ) -> CreateHandlerResult<'a>
363 + Send
364 + Sync;
365type CreateAfterHandler<M> = dyn for<'a> Fn(
366 &'a mut <M as CreatableModel>::CreateResult,
367 &'a <M as CreatableModel>::CreateOptions<'_>,
368 &'a crate::State,
369 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
370 ) -> CreateHandlerResult<'a>
371 + Send
372 + Sync;
373pub type CreateListenerList<M> =
374 Arc<ModelHandlerList<Arc<CreateHandler<M>>, Arc<CreateAfterHandler<M>>>>;
375
376#[async_trait::async_trait]
377pub trait CreatableModel: BaseModel + Send + Sync + 'static {
378 type CreateOptions<'a>: Send + Sync + Validate;
379 type CreateResult: Send;
380
381 fn get_create_handlers() -> &'static LazyLock<CreateListenerList<Self>>;
382
383 fn register_create_handler<
384 F: for<'a> Fn(
385 &'a mut Self::CreateOptions<'_>,
386 &'a mut InsertQueryBuilder,
387 &'a crate::State,
388 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
389 ) -> Pin<
390 Box<dyn Future<Output = Result<(), crate::database::DatabaseError>> + Send + 'a>,
391 > + Send
392 + Sync
393 + 'static,
394 >(
395 priority: ListenerPriority,
396 callback: F,
397 ) {
398 let erased = Arc::new(callback) as Arc<CreateHandler<Self>>;
399
400 Self::get_create_handlers().register_handler(priority, erased);
401 }
402
403 fn register_after_create_handler<
404 F: for<'a> Fn(
405 &'a mut Self::CreateResult,
406 &'a Self::CreateOptions<'_>,
407 &'a crate::State,
408 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
409 ) -> Pin<
410 Box<dyn Future<Output = Result<(), crate::database::DatabaseError>> + Send + 'a>,
411 > + Send
412 + Sync
413 + 'static,
414 >(
415 priority: ListenerPriority,
416 callback: F,
417 ) {
418 let erased = Arc::new(callback) as Arc<CreateAfterHandler<Self>>;
419
420 Self::get_create_handlers().register_after_handler(priority, erased);
421 }
422
423 async fn run_create_handlers(
424 options: &mut Self::CreateOptions<'_>,
425 query_builder: &mut InsertQueryBuilder,
426 state: &crate::State,
427 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
428 ) -> Result<(), crate::database::DatabaseError> {
429 let callbacks = Self::get_create_handlers()
430 .before_handlers
431 .read()
432 .iter()
433 .map(|l| l.callback.clone())
434 .collect::<Vec<_>>();
435
436 for callback in callbacks.iter() {
437 (*callback)(options, query_builder, state, transaction).await?;
438 }
439
440 Ok(())
441 }
442
443 async fn run_after_create_handlers(
444 result: &mut Self::CreateResult,
445 options: &Self::CreateOptions<'_>,
446 state: &crate::State,
447 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
448 ) -> Result<(), crate::database::DatabaseError> {
449 let callbacks = Self::get_create_handlers()
450 .after_handlers
451 .read()
452 .iter()
453 .map(|l| l.callback.clone())
454 .collect::<Vec<_>>();
455
456 for callback in callbacks.iter() {
457 (*callback)(result, options, state, transaction).await?;
458 }
459
460 Ok(())
461 }
462
463 async fn create_with_transaction(
464 state: &crate::State,
465 options: Self::CreateOptions<'_>,
466 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
467 ) -> Result<Self::CreateResult, crate::database::DatabaseError>;
468
469 async fn create(
470 state: &crate::State,
471 options: Self::CreateOptions<'_>,
472 ) -> Result<Self::CreateResult, crate::database::DatabaseError> {
473 let mut transaction = state.database.write().begin().await?;
474
475 let result = match Self::create_with_transaction(state, options, &mut transaction).await {
476 Ok(result) => result,
477 Err(err) => {
478 transaction.rollback().await?;
479 return Err(err);
480 }
481 };
482
483 transaction.commit().await?;
484
485 Ok(result)
486 }
487}
488
489type UpdateHandlerResult<'a> =
490 Pin<Box<dyn Future<Output = Result<(), crate::database::DatabaseError>> + Send + 'a>>;
491type UpdateHandler<M> = dyn for<'a> Fn(
492 &'a mut M,
493 &'a mut <M as UpdatableModel>::UpdateOptions,
494 &'a mut UpdateQueryBuilder,
495 &'a crate::State,
496 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
497 ) -> UpdateHandlerResult<'a>
498 + Send
499 + Sync;
500type UpdateAfterHandler<M> = dyn for<'a> Fn(
501 &'a mut M,
502 &'a crate::State,
503 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
504 ) -> UpdateHandlerResult<'a>
505 + Send
506 + Sync;
507pub type UpdateHandlerList<M> =
508 Arc<ModelHandlerList<Arc<UpdateHandler<M>>, Arc<UpdateAfterHandler<M>>>>;
509
510#[async_trait::async_trait]
511pub trait UpdatableModel: BaseModel + Send + Sync + 'static {
512 type UpdateOptions: Send + Sync + Default + ToSchema + DeserializeOwned + Serialize + Validate;
513
514 fn get_update_handlers() -> &'static LazyLock<UpdateHandlerList<Self>>;
515
516 fn register_update_handler<
517 F: for<'a> Fn(
518 &'a mut Self,
519 &'a mut Self::UpdateOptions,
520 &'a mut UpdateQueryBuilder,
521 &'a crate::State,
522 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
523 ) -> Pin<
524 Box<dyn Future<Output = Result<(), crate::database::DatabaseError>> + Send + 'a>,
525 > + Send
526 + Sync
527 + 'static,
528 >(
529 priority: ListenerPriority,
530 callback: F,
531 ) {
532 let erased = Arc::new(callback) as Arc<UpdateHandler<Self>>;
533
534 Self::get_update_handlers().register_handler(priority, erased);
535 }
536
537 fn register_after_update_handler<
538 F: for<'a> Fn(
539 &'a mut Self,
540 &'a crate::State,
541 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
542 ) -> Pin<
543 Box<dyn Future<Output = Result<(), crate::database::DatabaseError>> + Send + 'a>,
544 > + Send
545 + Sync
546 + 'static,
547 >(
548 priority: ListenerPriority,
549 callback: F,
550 ) {
551 let erased = Arc::new(callback) as Arc<UpdateAfterHandler<Self>>;
552
553 Self::get_update_handlers().register_after_handler(priority, erased);
554 }
555
556 async fn run_update_handlers(
557 &mut self,
558 options: &mut Self::UpdateOptions,
559 query_builder: &mut UpdateQueryBuilder,
560 state: &crate::State,
561 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
562 ) -> Result<(), crate::database::DatabaseError> {
563 let callbacks = Self::get_update_handlers()
564 .before_handlers
565 .read()
566 .iter()
567 .map(|l| l.callback.clone())
568 .collect::<Vec<_>>();
569
570 for callback in callbacks.iter() {
571 (*callback)(self, options, query_builder, state, transaction).await?;
572 }
573
574 Ok(())
575 }
576
577 async fn run_after_update_handlers(
578 &mut self,
579 state: &crate::State,
580 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
581 ) -> Result<(), crate::database::DatabaseError> {
582 let callbacks = Self::get_update_handlers()
583 .after_handlers
584 .read()
585 .iter()
586 .map(|l| l.callback.clone())
587 .collect::<Vec<_>>();
588
589 for callback in callbacks.iter() {
590 (*callback)(self, state, transaction).await?;
591 }
592
593 Ok(())
594 }
595
596 async fn update_with_transaction(
597 &mut self,
598 state: &crate::State,
599 options: Self::UpdateOptions,
600 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
601 ) -> Result<(), crate::database::DatabaseError>;
602
603 async fn update(
604 &mut self,
605 state: &crate::State,
606 options: Self::UpdateOptions,
607 ) -> Result<(), crate::database::DatabaseError> {
608 let mut transaction = state.database.write().begin().await?;
609
610 if let Err(err) = self
611 .update_with_transaction(state, options, &mut transaction)
612 .await
613 {
614 transaction.rollback().await?;
615 return Err(err);
616 }
617
618 transaction.commit().await?;
619
620 invalidate_cache_keys(&state.database, &self.cache_invalidation_keys()).await;
621
622 Ok(())
623 }
624}
625
626type DeleteHandlerResult<'a> = Pin<Box<dyn Future<Output = Result<(), anyhow::Error>> + Send + 'a>>;
627type DeleteHandler<M> = dyn for<'a> Fn(
628 &'a M,
629 &'a <M as DeletableModel>::DeleteOptions,
630 &'a crate::State,
631 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
632 ) -> DeleteHandlerResult<'a>
633 + Send
634 + Sync;
635type DeleteAfterHandler<M> = dyn for<'a> Fn(
636 &'a M,
637 &'a <M as DeletableModel>::DeleteOptions,
638 &'a crate::State,
639 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
640 ) -> DeleteHandlerResult<'a>
641 + Send
642 + Sync;
643pub type DeleteHandlerList<M> =
644 Arc<ModelHandlerList<Arc<DeleteHandler<M>>, Arc<DeleteAfterHandler<M>>>>;
645
646#[async_trait::async_trait]
647pub trait DeletableModel: BaseModel + Send + Sync + 'static {
648 type DeleteOptions: Send + Sync + Default + Clone;
649
650 fn get_delete_handlers() -> &'static LazyLock<DeleteHandlerList<Self>>;
651
652 fn register_delete_handler<
653 F: for<'a> Fn(
654 &'a Self,
655 &'a Self::DeleteOptions,
656 &'a crate::State,
657 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
658 )
659 -> Pin<Box<dyn Future<Output = Result<(), anyhow::Error>> + Send + 'a>>
660 + Send
661 + Sync
662 + 'static,
663 >(
664 priority: ListenerPriority,
665 callback: F,
666 ) {
667 let erased = Arc::new(callback) as Arc<DeleteHandler<Self>>;
668
669 Self::get_delete_handlers().register_handler(priority, erased);
670 }
671
672 fn register_after_delete_handler<
673 F: for<'a> Fn(
674 &'a Self,
675 &'a Self::DeleteOptions,
676 &'a crate::State,
677 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
678 )
679 -> Pin<Box<dyn Future<Output = Result<(), anyhow::Error>> + Send + 'a>>
680 + Send
681 + Sync
682 + 'static,
683 >(
684 priority: ListenerPriority,
685 callback: F,
686 ) {
687 let erased = Arc::new(callback) as Arc<DeleteAfterHandler<Self>>;
688
689 Self::get_delete_handlers().register_after_handler(priority, erased);
690 }
691
692 async fn run_delete_handlers(
693 &self,
694 options: &Self::DeleteOptions,
695 state: &crate::State,
696 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
697 ) -> Result<(), anyhow::Error> {
698 let callbacks = Self::get_delete_handlers()
699 .before_handlers
700 .read()
701 .iter()
702 .map(|l| l.callback.clone())
703 .collect::<Vec<_>>();
704
705 for callback in callbacks.iter() {
706 (*callback)(self, options, state, transaction).await?;
707 }
708
709 Ok(())
710 }
711
712 async fn run_after_delete_handlers(
713 &self,
714 options: &Self::DeleteOptions,
715 state: &crate::State,
716 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
717 ) -> Result<(), anyhow::Error> {
718 let callbacks = Self::get_delete_handlers()
719 .after_handlers
720 .read()
721 .iter()
722 .map(|l| l.callback.clone())
723 .collect::<Vec<_>>();
724
725 for callback in callbacks.iter() {
726 (*callback)(self, options, state, transaction).await?;
727 }
728
729 Ok(())
730 }
731
732 async fn delete_with_transaction(
733 &self,
734 state: &crate::State,
735 options: Self::DeleteOptions,
736 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
737 ) -> Result<(), anyhow::Error>;
738
739 async fn delete(
740 &self,
741 state: &crate::State,
742 options: Self::DeleteOptions,
743 ) -> Result<(), anyhow::Error> {
744 let mut transaction = state.database.write().begin().await?;
745
746 if let Err(err) = self
747 .delete_with_transaction(state, options, &mut transaction)
748 .await
749 {
750 transaction.rollback().await?;
751 return Err(err);
752 }
753
754 transaction.commit().await?;
755
756 invalidate_cache_keys(&state.database, &self.cache_invalidation_keys()).await;
757
758 Ok(())
759 }
760}
761
762type DuplicateHandlerResult<'a> =
763 Pin<Box<dyn Future<Output = Result<(), crate::database::DatabaseError>> + Send + 'a>>;
764type DuplicateHandler<M> = dyn for<'a> Fn(
765 &'a M,
766 &'a <M as DuplicableModel>::DuplicateOptions<'_>,
767 &'a crate::State,
768 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
769 ) -> DuplicateHandlerResult<'a>
770 + Send
771 + Sync;
772type DuplicateAfterHandler<M> = dyn for<'a> Fn(
773 &'a M,
774 &'a mut <M as DuplicableModel>::DuplicateResult,
775 &'a <M as DuplicableModel>::DuplicateOptions<'_>,
776 &'a crate::State,
777 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
778 ) -> DuplicateHandlerResult<'a>
779 + Send
780 + Sync;
781pub type DuplicateHandlerList<M> =
782 Arc<ModelHandlerList<Arc<DuplicateHandler<M>>, Arc<DuplicateAfterHandler<M>>>>;
783
784#[async_trait::async_trait]
785pub trait DuplicableModel: BaseModel + Send + Sync + 'static {
786 type DuplicateOptions<'a>: Send + Sync + Validate;
787 type DuplicateResult: Send;
788
789 fn get_duplicate_handlers() -> &'static LazyLock<DuplicateHandlerList<Self>>;
790
791 fn register_duplicate_handler<
792 F: for<'a> Fn(
793 &'a Self,
794 &'a Self::DuplicateOptions<'_>,
795 &'a crate::State,
796 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
797 ) -> DuplicateHandlerResult<'a>
798 + Send
799 + Sync
800 + 'static,
801 >(
802 priority: ListenerPriority,
803 callback: F,
804 ) {
805 let erased = Arc::new(callback) as Arc<DuplicateHandler<Self>>;
806
807 Self::get_duplicate_handlers().register_handler(priority, erased);
808 }
809
810 fn register_after_duplicate_handler<
811 F: for<'a> Fn(
812 &'a Self,
813 &'a mut Self::DuplicateResult,
814 &'a Self::DuplicateOptions<'_>,
815 &'a crate::State,
816 &'a mut sqlx::Transaction<'_, sqlx::Postgres>,
817 ) -> DuplicateHandlerResult<'a>
818 + Send
819 + Sync
820 + 'static,
821 >(
822 priority: ListenerPriority,
823 callback: F,
824 ) {
825 let erased = Arc::new(callback) as Arc<DuplicateAfterHandler<Self>>;
826
827 Self::get_duplicate_handlers().register_after_handler(priority, erased);
828 }
829
830 async fn run_duplicate_handlers(
831 &self,
832 options: &Self::DuplicateOptions<'_>,
833 state: &crate::State,
834 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
835 ) -> Result<(), crate::database::DatabaseError> {
836 let callbacks = Self::get_duplicate_handlers()
837 .before_handlers
838 .read()
839 .iter()
840 .map(|l| l.callback.clone())
841 .collect::<Vec<_>>();
842
843 for callback in callbacks.iter() {
844 (*callback)(self, options, state, transaction).await?;
845 }
846
847 Ok(())
848 }
849
850 async fn run_after_duplicate_handlers(
851 &self,
852 duplicated: &mut Self::DuplicateResult,
853 options: &Self::DuplicateOptions<'_>,
854 state: &crate::State,
855 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
856 ) -> Result<(), crate::database::DatabaseError> {
857 let callbacks = Self::get_duplicate_handlers()
858 .after_handlers
859 .read()
860 .iter()
861 .map(|l| l.callback.clone())
862 .collect::<Vec<_>>();
863
864 for callback in callbacks.iter() {
865 (*callback)(self, duplicated, options, state, transaction).await?;
866 }
867
868 Ok(())
869 }
870
871 async fn duplicate_with_transaction(
872 &self,
873 state: &crate::State,
874 options: Self::DuplicateOptions<'_>,
875 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
876 ) -> Result<Self::DuplicateResult, crate::database::DatabaseError>;
877
878 async fn duplicate(
879 &self,
880 state: &crate::State,
881 options: Self::DuplicateOptions<'_>,
882 ) -> Result<Self::DuplicateResult, crate::database::DatabaseError> {
883 let mut transaction = state.database.write().begin().await?;
884
885 let duplicated = match self
886 .duplicate_with_transaction(state, options, &mut transaction)
887 .await
888 {
889 Ok(duplicated) => duplicated,
890 Err(err) => {
891 transaction.rollback().await?;
892 return Err(err);
893 }
894 };
895
896 transaction.commit().await?;
897
898 Ok(duplicated)
899 }
900}
901
902pub const BY_UUID_CACHE_TTL: u64 = 10;
903
904#[async_trait::async_trait]
905pub trait ByUuid: BaseModel {
906 async fn by_uuid(
907 database: &crate::database::Database,
908 uuid: uuid::Uuid,
909 ) -> Result<Self, DatabaseError>;
910
911 async fn by_uuid_with_transaction(
912 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
913 uuid: uuid::Uuid,
914 ) -> Result<Self, DatabaseError>;
915
916 async fn by_uuid_cached(
917 database: &crate::database::Database,
918 uuid: uuid::Uuid,
919 ) -> Result<Self, anyhow::Error> {
920 database
921 .cache
922 .cached(
923 &format!("{}::{uuid}", Self::NAME),
924 BY_UUID_CACHE_TTL,
925 || Self::by_uuid(database, uuid),
926 )
927 .await
928 }
929
930 async fn by_uuid_optional(
931 database: &crate::database::Database,
932 uuid: uuid::Uuid,
933 ) -> Result<Option<Self>, DatabaseError> {
934 match Self::by_uuid(database, uuid).await {
935 Ok(res) => Ok(Some(res)),
936 Err(DatabaseError::Sqlx(sqlx::Error::RowNotFound)) => Ok(None),
937 Err(err) => Err(err),
938 }
939 }
940
941 async fn by_uuid_optional_with_transaction(
942 transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
943 uuid: uuid::Uuid,
944 ) -> Result<Option<Self>, DatabaseError> {
945 match Self::by_uuid_with_transaction(transaction, uuid).await {
946 Ok(res) => Ok(Some(res)),
947 Err(DatabaseError::Sqlx(sqlx::Error::RowNotFound)) => Ok(None),
948 Err(err) => Err(err),
949 }
950 }
951
952 async fn by_uuid_optional_cached(
953 database: &crate::database::Database,
954 uuid: uuid::Uuid,
955 ) -> Result<Option<Self>, anyhow::Error> {
956 match Self::by_uuid_cached(database, uuid).await {
957 Ok(res) => Ok(Some(res)),
958 Err(err)
959 if err.chain().any(|err| {
960 matches!(
961 err.downcast_ref::<DatabaseError>(),
962 Some(DatabaseError::Sqlx(sqlx::Error::RowNotFound))
963 )
964 }) =>
965 {
966 Ok(None)
967 }
968 Err(err) => Err(err),
969 }
970 }
971
972 #[inline]
973 fn get_fetchable(uuid: uuid::Uuid) -> Fetchable<Self> {
974 Fetchable {
975 uuid,
976 _model: PhantomData,
977 }
978 }
979
980 #[inline]
981 fn get_fetchable_from_row(row: &PgRow, column: impl AsRef<str>) -> Option<Fetchable<Self>> {
982 match row.try_get(column.as_ref()) {
983 Ok(uuid) => Some(Fetchable {
984 uuid,
985 _model: PhantomData,
986 }),
987 Err(_) => None,
988 }
989 }
990
991 async fn invalidate_cached(database: &crate::database::Database, uuid: uuid::Uuid) {
992 let key = compact_str::format_compact!("{}::{uuid}", Self::NAME);
993
994 invalidate_cache_keys(database, &[key]).await;
995 }
996}
997
998#[derive(Debug)]
999struct UnresolvedIdentifier;
1000
1001impl std::fmt::Display for UnresolvedIdentifier {
1002 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1003 f.write_str("identifier does not resolve to a row")
1004 }
1005}
1006
1007impl std::error::Error for UnresolvedIdentifier {}
1008
1009#[async_trait::async_trait]
1010pub trait ResolvableModel: ByUuid + Serialize + DeserializeOwned + Send + Sync {
1011 type Fingerprint: Serialize + Send;
1012
1013 fn uuid(&self) -> uuid::Uuid;
1014
1015 fn fingerprint(&self) -> Self::Fingerprint;
1016
1017 async fn resolve(
1018 database: &crate::database::Database,
1019 identifier: &str,
1020 ) -> Result<Option<Self>, anyhow::Error>;
1021
1022 async fn resolve_cached(
1023 database: &crate::database::Database,
1024 identifier: &str,
1025 ) -> Result<Option<Self>, anyhow::Error> {
1026 let key = format!(
1027 "{}::resolve::{}",
1028 Self::NAME,
1029 hex::encode(sha2::Sha256::digest(identifier.as_bytes()))
1030 );
1031
1032 if let Some(resolution) = database.cache.resolution(&key).await {
1033 if let Some(row) = Self::by_uuid_optional_cached(database, resolution.uuid).await?
1034 && rmp_serde::to_vec(&row.fingerprint())? == *resolution.fingerprint
1035 {
1036 return Ok(Some(row));
1037 }
1038
1039 database.cache.remove_resolution(&key).await;
1040 }
1041
1042 let resolution = database
1043 .cache
1044 .resolve(&key, || async {
1045 let Some(row) = Self::resolve(database, identifier).await? else {
1046 return Err(UnresolvedIdentifier.into());
1047 };
1048
1049 database
1050 .cache
1051 .set(
1052 &format!("{}::{}", Self::NAME, row.uuid()),
1053 BY_UUID_CACHE_TTL,
1054 &row,
1055 )
1056 .await?;
1057
1058 Ok(crate::cache::Resolution {
1059 uuid: row.uuid(),
1060 fingerprint: Arc::new(rmp_serde::to_vec(&row.fingerprint())?),
1061 })
1062 })
1063 .await;
1064
1065 match resolution {
1066 Ok(resolution) => Self::by_uuid_optional_cached(database, resolution.uuid).await,
1067 Err(err) if err.chain().any(|err| err.is::<UnresolvedIdentifier>()) => Ok(None),
1068 Err(err) => Err(err),
1069 }
1070 }
1071}
1072
1073#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
1074pub enum ListenerPriority {
1075 Highest,
1076 High,
1077 #[default]
1078 Normal,
1079 Low,
1080 Lowest,
1081}
1082
1083impl ListenerPriority {
1084 #[inline]
1085 fn rank(self) -> u8 {
1086 match self {
1087 Self::Highest => 5,
1088 Self::High => 4,
1089 Self::Normal => 3,
1090 Self::Low => 2,
1091 Self::Lowest => 1,
1092 }
1093 }
1094}
1095
1096impl PartialOrd for ListenerPriority {
1097 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1098 Some(self.cmp(other))
1099 }
1100}
1101
1102impl Ord for ListenerPriority {
1103 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1104 let self_rank = self.rank();
1105 let other_rank = other.rank();
1106
1107 other_rank.cmp(&self_rank)
1108 }
1109}
1110
1111impl<F: Send + Sync, AfterF: Send + Sync> crate::events::DisconnectEventHandler
1112 for ModelHandlerList<F, AfterF>
1113{
1114 #[inline]
1115 fn disconnect(&self, id: uuid::Uuid) {
1116 self.before_handlers.write().retain(|l| l.uuid != id);
1117 self.after_handlers.write().retain(|l| l.uuid != id);
1118 }
1119}
1120
1121pub struct ModelHandlerList<F: Send + Sync + 'static, AfterF: Send + Sync + 'static> {
1122 before_handlers: RwLock<Vec<ModelHandler<F>>>,
1123 after_handlers: RwLock<Vec<ModelHandler<AfterF>>>,
1124}
1125
1126impl<F: Send + Sync + 'static, AfterF: Send + Sync + 'static> Default
1127 for ModelHandlerList<F, AfterF>
1128{
1129 fn default() -> Self {
1130 Self {
1131 before_handlers: RwLock::new(Vec::new()),
1132 after_handlers: RwLock::new(Vec::new()),
1133 }
1134 }
1135}
1136
1137impl<F: Send + Sync + 'static, AfterF: Send + Sync + 'static> ModelHandlerList<F, AfterF> {
1138 pub fn register_handler(
1139 self: &Arc<Self>,
1140 priority: ListenerPriority,
1141 callback: F,
1142 ) -> ModelHandlerHandle {
1143 let (listener, aborter) = ModelHandler::new(callback, priority, self.clone());
1144
1145 let mut self_listeners = self.before_handlers.write();
1146 self_listeners.push(listener);
1147 self_listeners.sort_by_key(|a| a.priority);
1148
1149 aborter
1150 }
1151
1152 pub fn register_after_handler(
1153 self: &Arc<Self>,
1154 priority: ListenerPriority,
1155 callback: AfterF,
1156 ) -> ModelHandlerHandle {
1157 let (listener, aborter) = ModelHandler::new(callback, priority, self.clone());
1158
1159 let mut self_listeners = self.after_handlers.write();
1160 self_listeners.push(listener);
1161 self_listeners.sort_by_key(|a| a.priority);
1162
1163 aborter
1164 }
1165}
1166
1167pub struct ModelHandler<F: Send + Sync + 'static> {
1168 uuid: uuid::Uuid,
1169 priority: ListenerPriority,
1170
1171 pub callback: F,
1172}
1173
1174impl<F: Send + Sync + 'static> ModelHandler<F> {
1175 pub(crate) fn new(
1176 callback: F,
1177 priority: ListenerPriority,
1178 list: Arc<dyn crate::events::DisconnectEventHandler + Send + Sync>,
1179 ) -> (Self, ModelHandlerHandle) {
1180 let handler = Self {
1181 uuid: uuid::Uuid::new_v4(),
1182 priority,
1183 callback,
1184 };
1185 let handle = ModelHandlerHandle {
1186 list_ref: list,
1187 id: handler.uuid,
1188 };
1189 (handler, handle)
1190 }
1191}
1192
1193pub struct ModelHandlerHandle {
1194 list_ref: Arc<dyn crate::events::DisconnectEventHandler + Send + Sync>,
1195 id: uuid::Uuid,
1196}
1197
1198impl ModelHandlerHandle {
1199 pub fn disconnect(&self) {
1200 self.list_ref.disconnect(self.id);
1201 }
1202}
1203
1204#[derive(Serialize, Deserialize, Clone, Copy)]
1205pub struct Fetchable<M: ByUuid> {
1206 pub uuid: uuid::Uuid,
1207 #[serde(skip)]
1208 _model: PhantomData<M>,
1209}
1210
1211impl<M: ByUuid + Send> Fetchable<M> {
1212 #[inline]
1213 pub async fn fetch(&self, database: &crate::database::Database) -> Result<M, DatabaseError> {
1214 M::by_uuid(database, self.uuid).await
1215 }
1216
1217 #[inline]
1218 pub async fn fetch_cached(
1219 &self,
1220 database: &crate::database::Database,
1221 ) -> Result<M, anyhow::Error> {
1222 M::by_uuid_cached(database, self.uuid).await
1223 }
1224
1225 #[inline]
1226 pub async fn fetch_optional(
1227 &self,
1228 database: &crate::database::Database,
1229 ) -> Result<Option<M>, DatabaseError> {
1230 M::by_uuid_optional(database, self.uuid).await
1231 }
1232
1233 #[inline]
1234 pub async fn fetch_optional_cached(
1235 &self,
1236 database: &crate::database::Database,
1237 ) -> Result<Option<M>, anyhow::Error> {
1238 M::by_uuid_optional_cached(database, self.uuid).await
1239 }
1240}
1241
1242pub struct InsertQueryBuilder<'a> {
1243 table: &'a str,
1244 columns: Vec<&'a str>,
1245 expressions: Vec<String>,
1246 arguments: PgArguments,
1247 returning_clause: Option<&'a str>,
1248}
1249
1250impl<'a> InsertQueryBuilder<'a> {
1251 pub fn new(table: &'a str) -> Self {
1252 Self {
1253 table,
1254 columns: Vec::new(),
1255 expressions: Vec::new(),
1256 arguments: PgArguments::default(),
1257 returning_clause: None,
1258 }
1259 }
1260
1261 pub fn set<T: 'a + sqlx::Encode<'a, Postgres> + sqlx::Type<Postgres> + Send>(
1262 &mut self,
1263 column: &'a str,
1264 value: T,
1265 ) -> &mut Self {
1266 if self.columns.contains(&column) {
1267 return self;
1268 }
1269
1270 if self.arguments.add(value).is_ok() {
1271 self.columns.push(column);
1272 let idx = self.arguments.len();
1273 self.expressions.push(format!("${}", idx));
1274 }
1275
1276 self
1277 }
1278
1279 pub fn set_expr<T: 'a + sqlx::Encode<'a, Postgres> + sqlx::Type<Postgres> + Send>(
1280 &mut self,
1281 column: &'a str,
1282 expression: &str,
1283 values: Vec<T>,
1284 ) -> &mut Self {
1285 if self.columns.contains(&column) {
1286 return self;
1287 }
1288
1289 let start_len = self.arguments.len();
1290
1291 for value in values {
1292 if self.arguments.add(value).is_err() {
1293 return self;
1294 }
1295 }
1296
1297 let mut expr = expression.to_string();
1298 let added_count = self.arguments.len() - start_len;
1299
1300 for i in (1..=added_count).rev() {
1301 let global_idx = start_len + i;
1302 expr = expr.replace(&format!("${}", i), &format!("${}", global_idx));
1303 }
1304
1305 self.columns.push(column);
1306 self.expressions.push(expr);
1307
1308 self
1309 }
1310
1311 pub fn returning(mut self, clause: &'a str) -> Self {
1312 self.returning_clause = Some(clause);
1313 self
1314 }
1315
1316 fn build_sql(&self) -> String {
1317 let columns_sql = self.columns.join(", ");
1318 let values_sql = self.expressions.join(", ");
1319
1320 let mut sql = format!(
1321 "INSERT INTO {} ({}) VALUES ({})",
1322 self.table, columns_sql, values_sql
1323 );
1324
1325 if let Some(clause) = self.returning_clause {
1326 sql.push_str(" RETURNING ");
1327 sql.push_str(clause);
1328 }
1329
1330 sql
1331 }
1332
1333 pub async fn execute(
1334 self,
1335 executor: impl sqlx::Executor<'a, Database = Postgres>,
1336 ) -> Result<sqlx::postgres::PgQueryResult, sqlx::Error> {
1337 let sql = self.build_sql();
1338 sqlx::query_with(sqlx::AssertSqlSafe(sql), self.arguments)
1339 .execute(executor)
1340 .await
1341 }
1342
1343 pub async fn fetch_one(
1344 self,
1345 executor: impl sqlx::Executor<'a, Database = Postgres>,
1346 ) -> Result<sqlx::postgres::PgRow, sqlx::Error> {
1347 let sql = self.build_sql();
1348 sqlx::query_with(sqlx::AssertSqlSafe(sql), self.arguments)
1349 .fetch_one(executor)
1350 .await
1351 }
1352}
1353
1354pub struct PaginatedQueryBuilder<'a> {
1362 select: compact_str::CompactString,
1363 body: compact_str::CompactString,
1364 order_by: &'a str,
1365 arguments: Result<PgArguments, BoxDynError>,
1366}
1367
1368impl<'a> PaginatedQueryBuilder<'a> {
1369 pub fn new(
1370 select: impl Into<compact_str::CompactString>,
1371 body: impl Into<compact_str::CompactString>,
1372 order_by: &'a str,
1373 ) -> Self {
1374 Self {
1375 select: select.into(),
1376 body: body.into(),
1377 order_by,
1378 arguments: Ok(PgArguments::default()),
1379 }
1380 }
1381
1382 pub fn bind<T: sqlx::Encode<'a, Postgres> + sqlx::Type<Postgres>>(mut self, value: T) -> Self {
1383 if let Ok(arguments) = &mut self.arguments
1384 && let Err(err) = arguments.add(value)
1385 {
1386 self.arguments = Err(err);
1387 }
1388
1389 self
1390 }
1391
1392 pub async fn fetch<M: BaseModel>(
1393 self,
1394 database: &crate::database::Database,
1395 page: i64,
1396 per_page: i64,
1397 ) -> Result<Pagination<M>, DatabaseError> {
1398 let mut arguments = self.arguments.map_err(sqlx::Error::Encode)?;
1399 let count_arguments = arguments.clone();
1400 let offset = (page - 1) * per_page;
1401
1402 let limit_param = arguments.len() + 1;
1403 arguments.add(per_page).map_err(sqlx::Error::Encode)?;
1404 arguments.add(offset).map_err(sqlx::Error::Encode)?;
1405
1406 let mut connection = database.read().acquire().await?;
1407
1408 let rows = sqlx::query_with(
1409 sqlx::AssertSqlSafe(format!(
1410 "SELECT {} {} ORDER BY {} LIMIT ${} OFFSET ${}",
1411 self.select,
1412 self.body,
1413 self.order_by,
1414 limit_param,
1415 limit_param + 1
1416 )),
1417 arguments,
1418 )
1419 .fetch_all(&mut *connection)
1420 .await?;
1421
1422 let len = rows.len() as i64;
1423 let total = if len < per_page && (len > 0 || offset == 0) {
1424 offset + len
1425 } else {
1426 sqlx::query_scalar_with(
1427 sqlx::AssertSqlSafe(format!("SELECT COUNT(*) {}", self.body)),
1428 count_arguments,
1429 )
1430 .fetch_one(&mut *connection)
1431 .await?
1432 };
1433
1434 Ok(Pagination {
1435 total,
1436 per_page,
1437 page,
1438 data: rows
1439 .into_iter()
1440 .map(|row| M::map(None, &row))
1441 .try_collect_vec()?,
1442 })
1443 }
1444}
1445
1446pub struct UpdateQueryBuilder<'a> {
1447 builder: QueryBuilder<Postgres>,
1448 updated_fields: HashSet<&'a str>,
1449 has_set_fields: bool,
1450 has_where: bool,
1451}
1452
1453impl<'a> UpdateQueryBuilder<'a> {
1454 pub fn new(table: &'a str) -> Self {
1455 let mut builder = QueryBuilder::new("UPDATE ");
1456 builder.push(table);
1457 builder.push(" SET ");
1458
1459 Self {
1460 builder,
1461 updated_fields: HashSet::new(),
1462 has_set_fields: false,
1463 has_where: false,
1464 }
1465 }
1466
1467 pub fn set<T: 'a + sqlx::Encode<'a, Postgres> + sqlx::Type<Postgres> + Send>(
1470 &mut self,
1471 column: &'a str,
1472 value: Option<T>,
1473 ) -> &mut Self {
1474 let Some(value) = value else {
1475 return self;
1476 };
1477
1478 if !self.updated_fields.insert(column) {
1479 return self;
1480 }
1481
1482 if self.has_set_fields {
1483 self.builder.push(", ");
1484 }
1485
1486 self.builder.push(column);
1487 self.builder.push(" = ");
1488 self.builder.push_bind(value);
1489
1490 self.has_set_fields = true;
1491 self
1492 }
1493
1494 pub fn where_eq<T: 'a + sqlx::Encode<'a, Postgres> + sqlx::Type<Postgres> + Send>(
1495 &mut self,
1496 column: &'a str,
1497 value: T,
1498 ) -> &mut Self {
1499 if self.has_where {
1500 self.builder.push(" AND ");
1501 } else {
1502 self.builder.push(" WHERE ");
1503 self.has_where = true;
1504 }
1505
1506 self.builder.push(column);
1507 self.builder.push(" = ");
1508 self.builder.push_bind(value);
1509 self
1510 }
1511
1512 pub async fn execute(
1513 mut self,
1514 executor: impl sqlx::Executor<'a, Database = Postgres>,
1515 ) -> Result<sqlx::any::AnyQueryResult, sqlx::Error> {
1516 if !self.has_set_fields {
1517 return Ok(sqlx::any::AnyQueryResult::default());
1518 }
1519
1520 let query = self.builder.build();
1521 query.execute(executor).await.map(|r| r.into())
1522 }
1523}
1524
1525pub struct OrderedJson<T>(pub T);
1527
1528impl<T: Serialize> sqlx::Encode<'_, sqlx::Postgres> for OrderedJson<T> {
1529 fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
1530 serde_json::to_writer(&mut **buf, &self.0)?;
1531 Ok(IsNull::No)
1532 }
1533}
1534
1535impl<T> sqlx::Type<sqlx::Postgres> for OrderedJson<T> {
1536 fn type_info() -> PgTypeInfo {
1537 PgTypeInfo::with_oid(sqlx::postgres::types::Oid(114))
1539 }
1540}
1541
1542#[async_trait::async_trait]
1543pub trait IntoApiObject {
1544 type ApiObject: Send;
1545 type ExtraArgs<'a>: Send;
1546
1547 async fn into_api_object<'a>(
1548 self,
1549 state: &crate::State,
1550 args: Self::ExtraArgs<'a>,
1551 ) -> Result<Self::ApiObject, DatabaseError>;
1552}
1553
1554#[async_trait::async_trait]
1555pub trait IntoAdminApiObject {
1556 type AdminApiObject: Send;
1557 type ExtraArgs<'a>: Send;
1558
1559 async fn into_admin_api_object<'a>(
1560 self,
1561 state: &crate::State,
1562 args: Self::ExtraArgs<'a>,
1563 ) -> Result<Self::AdminApiObject, DatabaseError>;
1564}