utils.rs (4872B)
1 use chrono::{SecondsFormat, Utc}; 2 use serde::{Deserialize, Serialize}; 3 use serde_json::{Map, Value}; 4 use uuid::Uuid; 5 6 use crate::error::SqlError; 7 8 pub fn parse_json<T: for<'de> Deserialize<'de>>(s: &str) -> Result<T, SqlError> { 9 serde_json::from_str::<T>(s).map_err(SqlError::from) 10 } 11 12 pub fn uuidv4() -> String { 13 Uuid::new_v4().to_string() 14 } 15 16 pub fn time_created_on() -> String { 17 Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true) 18 } 19 20 pub fn to_object_map<T: Serialize>(opts: T) -> Result<Map<String, Value>, SqlError> { 21 let v = serde_json::to_value(opts).map_err(SqlError::from)?; 22 let obj = v 23 .as_object() 24 .ok_or_else(|| SqlError::SerializationError(String::from("Expected an object")))?; 25 Ok(obj.clone()) 26 } 27 28 pub fn to_partial_object_map<T: Serialize>(opts: T) -> Result<Map<String, Value>, SqlError> { 29 let v = serde_json::to_value(opts).map_err(SqlError::from)?; 30 let obj = v 31 .as_object() 32 .ok_or_else(|| SqlError::SerializationError(String::from("Expected an object")))?; 33 let mut filtered = Map::new(); 34 for (k, v) in obj.iter() { 35 if !v.is_null() { 36 filtered.insert(k.clone(), v.clone()); 37 } 38 } 39 Ok(filtered) 40 } 41 42 pub fn to_db_bind_value(value: &Value) -> Value { 43 match value { 44 Value::Bool(b) => Value::from(i64::from(*b)), 45 Value::Number(n) => { 46 if let Some(u) = n.as_u64() { 47 if u <= u32::MAX as u64 { 48 Value::from(u as u32) 49 } else { 50 Value::from(u) 51 } 52 } else if let Some(i) = n.as_i64() { 53 Value::from(i) 54 } else { 55 Value::from( 56 n.as_f64() 57 .expect("json number should map to u64, i64, or f64"), 58 ) 59 } 60 } 61 Value::String(s) => Value::from(s.clone()), 62 _ => Value::Null, 63 } 64 } 65 66 pub fn build_where_clause_eq<T: Serialize>(filter: &T) -> Result<(String, Vec<Value>), SqlError> { 67 let obj = to_partial_object_map(filter)?; 68 if obj.is_empty() { 69 return Ok((String::new(), Vec::new())); 70 } 71 let mut clauses = Vec::with_capacity(obj.len()); 72 let mut binds = Vec::with_capacity(obj.len()); 73 for (k, v) in obj { 74 clauses.push(format!("{k} = ?")); 75 binds.push(to_db_bind_value(&v)); 76 } 77 Ok((format!(" WHERE {}", clauses.join(" AND ")), binds)) 78 } 79 80 pub fn build_insert_query_with_meta( 81 table: &str, 82 meta: &[(&str, Value)], 83 fields: &Map<String, Value>, 84 ) -> (String, Vec<Value>) { 85 let mut cols: Vec<String> = meta.iter().map(|(k, _)| k.to_string()).collect(); 86 cols.extend(fields.keys().cloned()); 87 let meta_binds: Vec<Value> = meta.iter().map(|(_, v)| to_db_bind_value(v)).collect(); 88 let field_binds: Vec<Value> = fields.values().map(to_db_bind_value).collect(); 89 let placeholders = (0..cols.len()) 90 .map(|_| "?") 91 .collect::<Vec<&str>>() 92 .join(","); 93 let sql = format!( 94 "INSERT INTO {table} ({}) VALUES ({});", 95 cols.join(","), 96 placeholders 97 ); 98 let mut binds = Vec::with_capacity(cols.len()); 99 binds.extend(meta_binds); 100 binds.extend(field_binds); 101 (sql, binds) 102 } 103 104 pub fn build_select_query_with_meta<T: Serialize>( 105 table: &str, 106 filter: Option<&T>, 107 ) -> (String, Vec<Value>) { 108 let (where_clause, binds) = match filter { 109 Some(f) => build_where_clause_eq(f).unwrap_or_default(), 110 None => (String::new(), Vec::new()), 111 }; 112 let sql = format!("SELECT * FROM {table}{where_clause};"); 113 (sql, binds) 114 } 115 116 pub fn parse_query_value(v: &Value) -> Result<Value, SqlError> { 117 Ok(match v { 118 Value::Bool(b) => { 119 if *b { 120 serde_json::json!(1) 121 } else { 122 serde_json::json!(0) 123 } 124 } 125 Value::Null => Value::Null, 126 Value::Number(_) | Value::String(_) => v.clone(), 127 other => { 128 return Err(SqlError::InvalidArgument(other.to_string())); 129 } 130 }) 131 } 132 133 pub fn to_params_json<T: Serialize>(v: T) -> Result<String, SqlError> { 134 serde_json::to_string(&v).map_err(SqlError::from) 135 } 136 137 fn with_transaction_inner<E, T>( 138 exec: &E, 139 f: &mut dyn FnMut() -> Result<T, SqlError>, 140 ) -> Result<T, SqlError> 141 where 142 E: crate::SqlExecutor, 143 { 144 exec.begin()?; 145 match f() { 146 Ok(v) => { 147 exec.commit()?; 148 Ok(v) 149 } 150 Err(e) => { 151 let _ = exec.rollback(); 152 Err(e) 153 } 154 } 155 } 156 157 pub fn with_transaction<E, F, T>(exec: &E, f: F) -> Result<T, SqlError> 158 where 159 E: crate::SqlExecutor, 160 F: FnOnce() -> Result<T, SqlError>, 161 { 162 let mut f = Some(f); 163 with_transaction_inner(exec, &mut || { 164 let f = f.take().expect("transaction closure already used"); 165 f() 166 }) 167 }