Skip to content

Commit

Permalink
feat: add insert_without_defined_key method
Browse files Browse the repository at this point in the history
Introduce a new method `insert_without_defined_key` to insert rows with user-defined or backend-generated IDs.
  • Loading branch information
izyuumi committed Jul 8, 2024
1 parent 5fd4aae commit dc8e0ed
Showing 1 changed file with 97 additions and 54 deletions.
151 changes: 97 additions & 54 deletions src/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,12 @@
//! Both `insert` and `insert_if_unique` methods return a `Result<String, String>`, where `Ok(String)` contains the ID of the inserted row,
//! and `Err(String)` contains an error message in case of failure.
use crate::{
SupabaseClient,
generate_random_id
};
use serde_json::{
json,
Value
};
use reqwest::{
Client,
Response
};
use crate::{generate_random_id, SupabaseClient};
use reqwest::{Client, Response};
use serde_json::{json, Value};

impl SupabaseClient {
/// Inserts a new row into the specified table.
/// Inserts a new row into the specified table with automatically generated ID for column `id`.
///
/// # Arguments
/// * `table_name` - A string slice that holds the name of the table.
Expand All @@ -64,40 +55,33 @@ impl SupabaseClient {
/// ```rust
/// // Initialize the Supabase client
/// let client = SupabaseClient::new("your_supabase_url", "your_supabase_key");
///
///
/// // This will insert a new row into the table
/// let insert_result = client.insert(
/// "your_table_name",
/// json!(
/// {"column_name": "value"}
/// )
/// ).await;
/// ```
///
///
/// ```
///
///
/// # Returns
/// This method returns a `Result<String, String>`. On success, it returns `Ok(String)` with the new row's ID,
/// and on failure, it returns `Err(String)` with an error message.
pub async fn insert(
&self,
table_name: &str,
mut body: Value
) -> Result<String, String> {

pub async fn insert(&self, table_name: &str, mut body: Value) -> Result<String, String> {
let endpoint: String = format!("{}/rest/v1/{}", self.url, table_name);

#[cfg(feature = "rustls")]
let client = Client::builder().use_rustls_tls().build().unwrap();

#[cfg(not(feature = "rustls"))]
let client = Client::new();


#[cfg(feature = "nightly")]
use crate::nightly::print_nightly_warning;
#[cfg(feature = "nightly")]
print_nightly_warning();


let new_id: i64 = generate_random_id();
body["id"] = json!(new_id);
Expand All @@ -110,21 +94,91 @@ impl SupabaseClient {
.header("x_client_info", "supabase-rs/0.3.3")
.body(body.to_string())
.send()
.await {
Ok(response) => response,
Err(e) => return Err(e.to_string())
};
.await
{
Ok(response) => response,
Err(e) => return Err(e.to_string()),
};

if response.status().is_success() {
Ok(new_id.to_string())
} else if response.status().as_u16() == 409 {
println!("\x1b[31mError 409: Duplicate entry. The value you're trying to insert may already exist in a column with a UNIQUE constraint.\x1b[0m");

return Err("\x1b[31mError 409: Duplicate entry. The value you're trying to insert may already exist in a column with a UNIQUE constraint.\x1b[0m".to_string());
} else {
println!("\x1b[31mError: {:?}\x1b[0m", response);
return Err(response.status().to_string());
}
}

/// Inserts a new row into the specified table with a user-defined ID or Supabase backend generated ID.
///
/// # Arguments
/// * `table_name` - A string slice that holds the name of the table.
/// * `body` - A JSON value containing the data to be inserted.
///
/// # Example
/// ```rust
/// // Initialize the Supabase client
/// let client = SupabaseClient::new("your_supabase_url", "your_supabase_key");
///
/// // This will insert a new row into the table
/// let insert_result = client.insert(
/// "your_table_name",
/// json!(
/// {
/// "id": "your_id", // Optional
/// "column_name": "value"
/// }
/// )
/// ).await;
/// ```
///
/// # Returns
/// This method returns a `Result<(), String>`. On success, it returns `Ok(())`,
/// and on failure, it returns `Err(String)` with an error message.
pub async fn insert_without_defined_key(
&self,
table_name: &str,
mut body: Value,
) -> Result<(), String> {
let endpoint: String = format!("{}/rest/v1/{}", self.url, table_name);

#[cfg(feature = "rustls")]
let client = Client::builder().use_rustls_tls().build().unwrap();

#[cfg(not(feature = "rustls"))]
let client = Client::new();

#[cfg(feature = "nightly")]
use crate::nightly::print_nightly_warning;
#[cfg(feature = "nightly")]
print_nightly_warning();

let response: Response = match client
.post(&endpoint)
.header("apikey", &self.api_key)
.header("Authorization", format!("Bearer {}", &self.api_key))
.header("Content-Type", "application/json")
.header("x_client_info", "supabase-rs/0.3.3")
.body(body.to_string())
.send()
.await
{
Ok(response) => response,
Err(e) => return Err(e.to_string()),
};

if response.status().is_success() {
Ok(())
} else if response.status().as_u16() == 409 {
println!("\x1b[31mError 409: Duplicate entry. The value you're trying to insert may already exist in a column with a UNIQUE constraint.\x1b[0m");

return Err("\x1b[31mError 409: Duplicate entry. The value you're trying to insert may already exist in a column with a UNIQUE constraint.\x1b[0m".to_string());
} else {
println!("\x1b[31mError: {:?}\x1b[0m", response);
return Err(response.status().to_string())
return Err(response.status().to_string());
}
}

Expand All @@ -138,54 +192,43 @@ impl SupabaseClient {
/// ```rust
/// // Initialize the Supabase client
/// let client = SupabaseClient::new("your_supabase_url", "your_supabase_key");
///
///
/// // This will insert a new row into the table if the value is unique
/// let unique_insert_result = client.insert_if_unique(
/// "your_table_name",
/// json!({"unique_column_name": "unique_value"})
/// ).await;
/// ``` ```
///
///
///
///
/// # Returns
/// This method returns a `Result<String, String>`. On success, it returns `Ok(String)` with the new row's ID,
/// and on failure, it returns `Err(String)` with an error message indicating a duplicate entry.
pub async fn insert_if_unique(
&self,
table_name: &str,
body: Value
) -> Result<String, String> {
pub async fn insert_if_unique(&self, table_name: &str, body: Value) -> Result<String, String> {
let conditions: &serde_json::Map<String, Value> = match body.as_object() {
Some(map) => map,
None => {
println!("\x1b[31mFailed to parse body as JSON object\x1b[0m");
return Err("Failed to parse body as JSON object".to_string());
},
}
};

// Check if any row in the table matches all the column-value pairs in the body
let mut query: crate::query::QueryBuilder = self.select(table_name);
for (
column_name,
column_value
) in conditions {
for (column_name, column_value) in conditions {
// turn column_value into a string before passing it to the query
// ONLY if it's NOT a string
let column_value_str: String = match column_value {
Value::String(s) => s.clone(),
_ => column_value.to_string(),
};


// our query is sensitive to the type of the column value
query = query.eq(
column_name,
column_value_str.as_str()
);
query = query.eq(column_name, column_value_str.as_str());
}

let response: Result<Vec<Value>, String> = query.execute().await;

// If no existing row matches all conditions, proceed with the insert
if let Ok(results) = response {
if results.is_empty() {
Expand All @@ -195,7 +238,7 @@ impl SupabaseClient {
println!("\x1b[31mFailed to execute select query\x1b[0m");
return Err("Failed to execute select query".to_string());
}

Err("Error 409: Duplicate entry. The values you're trying to insert may already exist in a column with a UNIQUE constraint".to_string())
}
}
}

0 comments on commit dc8e0ed

Please sign in to comment.