Execute a SELECT query using a pooled connection
(&self, sql: &str)
| 60 | |
| 61 | /// Execute a SELECT query using a pooled connection |
| 62 | pub async fn query(&self, sql: &str) -> Result<DbResponse, ReadOnlyError> { |
| 63 | // Ensure this is a read-only operation |
| 64 | if !is_read_only_query(sql) { |
| 65 | return Err(ReadOnlyError::WriteNotAllowed); |
| 66 | } |
| 67 | |
| 68 | let conn = self.pool.acquire().await?; |
| 69 | |
| 70 | // Execute query using rusqlite |
| 71 | let mut stmt = conn.prepare(sql)?; |
| 72 | let column_names: Vec<String> = stmt.column_names() |
| 73 | .iter() |
| 74 | .map(|s| s.to_string()) |
| 75 | .collect(); |
| 76 | |
| 77 | let rows = stmt.query_map([], |row| { |
| 78 | let mut values = Vec::new(); |
| 79 | for i in 0..column_names.len() { |
| 80 | // Convert SQLite values to bytes for DbResponse compatibility |
| 81 | let value = match row.get::<_, rusqlite::types::Value>(i)? { |
| 82 | rusqlite::types::Value::Null => None, |
| 83 | rusqlite::types::Value::Integer(i) => Some(i.to_string().into_bytes()), |
| 84 | rusqlite::types::Value::Real(f) => Some(f.to_string().into_bytes()), |
| 85 | rusqlite::types::Value::Text(s) => Some(s.into_bytes()), |
| 86 | rusqlite::types::Value::Blob(b) => Some(b), |
| 87 | }; |
| 88 | values.push(value); |
| 89 | } |
| 90 | Ok(values) |
| 91 | })?; |
| 92 | |
| 93 | let mut result_rows = Vec::new(); |
| 94 | for row_result in rows { |
| 95 | result_rows.push(row_result?); |
| 96 | } |
| 97 | |
| 98 | let rows_affected = result_rows.len(); |
| 99 | Ok(DbResponse { |
| 100 | columns: column_names, |
| 101 | rows: result_rows, |
| 102 | rows_affected, |
| 103 | }) |
| 104 | } |
| 105 | |
| 106 | /// Execute a prepared statement with parameters |
| 107 | pub async fn query_with_params( |