sql_middleware/sqlite/
query.rs

1use rusqlite::types::Value;
2use rusqlite::{Statement, ToSql};
3
4use crate::middleware::{ResultSet, RowValues, SqlMiddlewareDbError};
5
6/// Extract a `RowValues` from a `SQLite` row.
7///
8/// # Errors
9///
10/// Returns `SqlMiddlewareDbError` if the value cannot be converted.
11pub fn sqlite_extract_value_sync(
12    row: &rusqlite::Row,
13    idx: usize,
14) -> Result<RowValues, SqlMiddlewareDbError> {
15    let value: Value = row.get(idx).map_err(SqlMiddlewareDbError::SqliteError)?;
16    match value {
17        Value::Null => Ok(RowValues::Null),
18        Value::Integer(i) => Ok(RowValues::Int(i)),
19        Value::Real(f) => Ok(RowValues::Float(f)),
20        Value::Text(s) => Ok(RowValues::Text(s)),
21        Value::Blob(b) => Ok(RowValues::Blob(b)),
22    }
23}
24
25/// Build a result set from a `SQLite` query
26/// Only SELECT queries return rows affected. If a DML is sent, it does run it.
27/// If there's more than one query in the statement, idk which statement will be run.
28///
29/// # Errors
30/// Returns `SqlMiddlewareDbError::ExecutionError` if query execution or result processing fails.
31pub fn build_result_set(
32    stmt: &mut Statement,
33    params: &[Value],
34) -> Result<ResultSet, SqlMiddlewareDbError> {
35    let param_refs: Vec<&dyn ToSql> = params.iter().map(|v| v as &dyn ToSql).collect();
36    let column_names: Vec<String> = stmt
37        .column_names()
38        .iter()
39        .map(std::string::ToString::to_string)
40        .collect();
41
42    // Store column names once in the result set
43    let column_names_rc = std::sync::Arc::new(column_names);
44
45    let mut rows_iter = stmt.query(&param_refs[..])?;
46    // Create result set with default capacity
47    let mut result_set = ResultSet::with_capacity(10);
48    result_set.set_column_names(column_names_rc);
49
50    while let Some(row) = rows_iter.next()? {
51        let mut row_values = Vec::new();
52
53        let col_count = result_set
54            .get_column_names()
55            .ok_or_else(|| {
56                SqlMiddlewareDbError::ExecutionError("No column names available".to_string())
57            })?
58            .len();
59
60        for i in 0..col_count {
61            let value = sqlite_extract_value_sync(row, i)?;
62            row_values.push(value);
63        }
64
65        result_set.add_row_values(row_values);
66    }
67
68    Ok(result_set)
69}