use std::collections::HashMap;
use std::hash::Hash;
use serde_json::Value;
use crate::{quote, quote_identifier};
pub fn build_insert_sql<K>(table: &str, data: HashMap<K, Value>) -> String
where
K: AsRef<str> + Eq + Hash,
{
let mut columns = Vec::new();
let mut values = Vec::new();
for (key, value) in data {
columns.push(quote_identifier(key.as_ref()));
let val_str = match value {
Value::Object(_) => quote(serde_json::to_string(&value).unwrap().as_str()),
Value::Array(_) => quote(serde_json::to_string(&value).unwrap().as_str()),
Value::String(s) => quote(&s),
Value::Number(n) => n.to_string(),
Value::Bool(b) => b.to_string(),
Value::Null => "NULL".to_string(),
};
values.push(val_str);
}
format!(
"INSERT INTO {} ({}) VALUES ({})",
quote_identifier(table.trim()),
columns.join(", "),
values.join(", ")
)
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_insert_single() {
let mut data = HashMap::new();
data.insert("name".to_string(), json!("John"));
let sql = build_insert_sql("users", data);
assert_eq!(sql, "INSERT INTO \"users\" (\"name\") VALUES ('John')");
}
#[test]
fn test_insert_multiple() {
let mut data = HashMap::new();
data.insert("name".to_string(), json!("John"));
data.insert("age".to_string(), json!(30));
let sql = build_insert_sql("users", data);
let valid1 = "INSERT INTO \"users\" (\"name\", \"age\") VALUES ('John', 30)";
let valid2 = "INSERT INTO \"users\" (\"age\", \"name\") VALUES (30, 'John')";
assert!(sql == valid1 || sql == valid2, "Generated SQL: {}", sql);
}
#[test]
fn test_insert_types() {
let mut data = HashMap::new();
data.insert("is_active".to_string(), json!(true));
data.insert("score".to_string(), json!(99.5));
data.insert("description".to_string(), json!(null));
let sql = build_insert_sql("stats", data);
assert!(sql.contains("INSERT INTO \"stats\""));
assert!(sql.contains("is_active"));
assert!(sql.contains("true"));
assert!(sql.contains("score"));
assert!(sql.contains("99.5"));
assert!(sql.contains("description"));
assert!(sql.contains("NULL"));
}
#[test]
fn test_insert_str_keys() {
let mut data = HashMap::new();
data.insert("name", json!("Jane"));
let sql = build_insert_sql("users", data);
assert_eq!(sql, "INSERT INTO \"users\" (\"name\") VALUES ('Jane')");
}
}