atmosphere_core/schema/
create.rs

1use crate::{
2    Bind, Error, Result,
3    hooks::{self, HookInput, HookStage, Hooks},
4    query::{QueryError, QueryResult},
5    schema::Table,
6};
7
8use async_trait::async_trait;
9use sqlx::{Executor, IntoArguments, database::Database};
10
11/// Trait for creating rows in a database.
12///
13/// This trait provides the functionality to create new rows in a table represented by a struct implementing
14/// `Table`, `Bind`, and `Hooks`. It defines an asynchronous method for inserting a new row into the database
15/// using a given executor. The trait ensures that all necessary hooks are executed at the appropriate stages
16/// of the operation.
17#[async_trait]
18pub trait Create: Table + Bind + Hooks + Sync + 'static {
19    /// Creates a new row in the database. This method builds the SQL insert query,
20    /// binds the necessary values, executes the query, and triggers the relevant hooks at different stages
21    /// (pre-binding and post-execution).
22    async fn create<'e, E>(
23        &mut self,
24        executor: E,
25    ) -> Result<<crate::Driver as sqlx::Database>::QueryResult>
26    where
27        E: Executor<'e, Database = crate::Driver>,
28        for<'q> <crate::Driver as Database>::Arguments<'q>: IntoArguments<'q, crate::Driver> + Send;
29}
30
31#[async_trait]
32impl<T> Create for T
33where
34    T: Table + Bind + Hooks + Sync + 'static,
35{
36    async fn create<'e, E>(
37        &mut self,
38        executor: E,
39    ) -> Result<<crate::Driver as sqlx::Database>::QueryResult>
40    where
41        E: Executor<'e, Database = crate::Driver>,
42        for<'q> <crate::Driver as Database>::Arguments<'q>: IntoArguments<'q, crate::Driver> + Send,
43    {
44        let query = crate::runtime::sql::insert::<T>();
45
46        hooks::execute(HookStage::PreBind, &query, HookInput::Row(self)).await?;
47
48        let mut builder = sqlx::query(query.sql());
49
50        for c in query.bindings().columns() {
51            builder = self.bind(c, builder).unwrap();
52        }
53
54        let res = builder
55            .persistent(false)
56            .execute(executor)
57            .await
58            .map_err(QueryError::from)
59            .map_err(Error::Query);
60
61        hooks::execute(
62            HookStage::PostExec,
63            &query,
64            QueryResult::Execution(&res).into(),
65        )
66        .await?;
67
68        res
69    }
70}