sqlx_sqlite_util.rs (3028B)
1 #![forbid(unsafe_code)] 2 3 use crate::error::SqlError; 4 use serde_json::{Map, Value}; 5 use sqlx::sqlite::{SqliteArguments, SqliteRow}; 6 use sqlx::{Column, Row, TypeInfo, ValueRef}; 7 8 #[derive(Debug)] 9 pub enum SqliteBindValue { 10 Null, 11 Integer(i64), 12 Real(f64), 13 Text(String), 14 } 15 16 pub fn parse_params(params_json: &str) -> Result<Vec<SqliteBindValue>, SqlError> { 17 let vals: Vec<Value> = serde_json::from_str(params_json) 18 .map_err(|e| SqlError::SerializationError(e.to_string()))?; 19 vals.into_iter() 20 .map(|v| match v { 21 Value::Null => Ok(SqliteBindValue::Null), 22 Value::Bool(b) => Ok(SqliteBindValue::Integer(i64::from(b))), 23 Value::Number(n) => { 24 if let Some(i) = n.as_i64() { 25 Ok(SqliteBindValue::Integer(i)) 26 } else if let Some(u) = n.as_u64() { 27 let value = i64::try_from(u).map_err(|_| { 28 SqlError::InvalidArgument("integer bind exceeds i64".to_string()) 29 })?; 30 Ok(SqliteBindValue::Integer(value)) 31 } else if let Some(f) = n.as_f64() { 32 Ok(SqliteBindValue::Real(f)) 33 } else { 34 Err(SqlError::InvalidArgument("unsupported number".to_string())) 35 } 36 } 37 Value::String(s) => Ok(SqliteBindValue::Text(s)), 38 other => Err(SqlError::InvalidArgument(format!( 39 "unsupported bind value: {}", 40 other 41 ))), 42 }) 43 .collect() 44 } 45 46 pub fn bind_params<'q>( 47 query: sqlx::query::Query<'q, sqlx::Sqlite, SqliteArguments>, 48 params: Vec<SqliteBindValue>, 49 ) -> Result<sqlx::query::Query<'q, sqlx::Sqlite, SqliteArguments>, SqlError> { 50 let mut query = query; 51 for param in params { 52 query = match param { 53 SqliteBindValue::Null => query.bind(Option::<String>::None), 54 SqliteBindValue::Integer(value) => query.bind(value), 55 SqliteBindValue::Real(value) => query.bind(value), 56 SqliteBindValue::Text(value) => query.bind(value), 57 }; 58 } 59 Ok(query) 60 } 61 62 pub fn row_to_json(row: &SqliteRow) -> Result<Value, SqlError> { 63 let mut obj = Map::new(); 64 for (index, column) in row.columns().iter().enumerate() { 65 let raw = row.try_get_raw(index)?; 66 let value = if raw.is_null() { 67 Value::Null 68 } else { 69 match raw.type_info().name() { 70 "INTEGER" | "BOOLEAN" => Value::from(row.try_get::<i64, _>(index)?), 71 "REAL" => Value::from(row.try_get::<f64, _>(index)?), 72 "TEXT" | "DATE" | "TIME" | "DATETIME" => { 73 Value::from(row.try_get::<String, _>(index)?) 74 } 75 "BLOB" => Value::Null, 76 _ => return Err(SqlError::InvalidQuery(raw.type_info().name().to_string())), 77 } 78 }; 79 obj.insert(column.name().to_string(), value); 80 } 81 Ok(Value::Object(obj)) 82 }