lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

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 }