Skip to main content

supabase_client_query/
insert.rs

1use std::marker::PhantomData;
2
3use serde::de::DeserializeOwned;
4
5use supabase_client_core::SupabaseResponse;
6
7use crate::backend::QueryBackend;
8use crate::modifier::Modifiable;
9use crate::sql::{ParamStore, SqlParts};
10
11/// Builder for INSERT queries. Implements Modifiable (for count).
12/// Call `.select()` to add RETURNING clause.
13pub struct InsertBuilder<T> {
14    pub(crate) backend: QueryBackend,
15    pub(crate) parts: SqlParts,
16    pub(crate) params: ParamStore,
17    pub(crate) _marker: PhantomData<T>,
18}
19
20impl<T> Modifiable for InsertBuilder<T> {
21    fn parts_mut(&mut self) -> &mut SqlParts {
22        &mut self.parts
23    }
24}
25
26impl<T> InsertBuilder<T> {
27    /// Override the schema for this query.
28    ///
29    /// Generates `"schema"."table"` instead of the default schema.
30    pub fn schema(mut self, schema: &str) -> Self {
31        self.parts.schema_override = Some(schema.to_string());
32        self
33    }
34
35    /// Add RETURNING clause to get inserted rows back.
36    pub fn select(mut self) -> Self {
37        self.parts.returning = Some("*".to_string());
38        self
39    }
40
41    /// Add RETURNING clause with specific columns.
42    pub fn select_columns(mut self, columns: &str) -> Self {
43        if columns == "*" || columns.is_empty() {
44            self.parts.returning = Some("*".to_string());
45        } else {
46            let quoted = columns
47                .split(',')
48                .map(|c| {
49                    let c = c.trim();
50                    if c.contains('(') || c.contains('*') || c.contains('"') {
51                        c.to_string()
52                    } else {
53                        format!("\"{}\"", c)
54                    }
55                })
56                .collect::<Vec<_>>()
57                .join(", ");
58            self.parts.returning = Some(quoted);
59        }
60        self
61    }
62}
63
64// REST-only mode: only DeserializeOwned + Send needed
65#[cfg(not(feature = "direct-sql"))]
66impl<T> InsertBuilder<T>
67where
68    T: DeserializeOwned + Send,
69{
70    /// Execute the INSERT query.
71    pub async fn execute(self) -> SupabaseResponse<T> {
72        let QueryBackend::Rest { ref http, ref base_url, ref api_key, ref schema } = self.backend;
73        let (url, headers, body) = match crate::postgrest::build_postgrest_insert(
74            base_url, &self.parts, &self.params,
75        ) {
76            Ok(r) => r,
77            Err(e) => return SupabaseResponse::error(
78                supabase_client_core::SupabaseError::QueryBuilder(e),
79            ),
80        };
81        crate::postgrest_execute::execute_rest(
82            http, reqwest::Method::POST, &url, headers, Some(body), api_key, schema, &self.parts,
83        ).await
84    }
85}
86
87// Direct-SQL mode: additional FromRow + Unpin bounds
88#[cfg(feature = "direct-sql")]
89impl<T> InsertBuilder<T>
90where
91    T: DeserializeOwned + Send + Unpin + for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>,
92{
93    /// Execute the INSERT query.
94    pub async fn execute(self) -> SupabaseResponse<T> {
95        match &self.backend {
96            QueryBackend::Rest { http, base_url, api_key, schema } => {
97                let (url, headers, body) = match crate::postgrest::build_postgrest_insert(
98                    base_url, &self.parts, &self.params,
99                ) {
100                    Ok(r) => r,
101                    Err(e) => return SupabaseResponse::error(
102                        supabase_client_core::SupabaseError::QueryBuilder(e),
103                    ),
104                };
105                crate::postgrest_execute::execute_rest(
106                    http, reqwest::Method::POST, &url, headers, Some(body), api_key, schema, &self.parts,
107                ).await
108            }
109            QueryBackend::DirectSql { pool } => {
110                crate::execute::execute_typed::<T>(pool, &self.parts, &self.params).await
111            }
112        }
113    }
114}