Execute a prepared statement with parameters
(
&self,
sql: &str,
params: &[&dyn rusqlite::ToSql]
)
| 105 | |
| 106 | /// Execute a prepared statement with parameters |
| 107 | pub async fn query_with_params( |
| 108 | &self, |
| 109 | sql: &str, |
| 110 | params: &[&dyn rusqlite::ToSql] |
| 111 | ) -> Result<DbResponse, ReadOnlyError> { |
| 112 | // Ensure this is a read-only operation |
| 113 | if !is_read_only_query(sql) { |
| 114 | return Err(ReadOnlyError::WriteNotAllowed); |
| 115 | } |
| 116 | |
| 117 | let conn = self.pool.acquire().await?; |
| 118 | |
| 119 | let mut stmt = conn.prepare(sql)?; |
| 120 | let column_names: Vec<String> = stmt.column_names() |
| 121 | .iter() |
| 122 | .map(|s| s.to_string()) |
| 123 | .collect(); |
| 124 | |
| 125 | let rows = stmt.query_map(params, |row| { |
| 126 | let mut values = Vec::new(); |
| 127 | for i in 0..column_names.len() { |
| 128 | let value = match row.get::<_, rusqlite::types::Value>(i)? { |
| 129 | rusqlite::types::Value::Null => None, |
| 130 | rusqlite::types::Value::Integer(i) => Some(i.to_string().into_bytes()), |
| 131 | rusqlite::types::Value::Real(f) => Some(f.to_string().into_bytes()), |
| 132 | rusqlite::types::Value::Text(s) => Some(s.into_bytes()), |
| 133 | rusqlite::types::Value::Blob(b) => Some(b), |
| 134 | }; |
| 135 | values.push(value); |
| 136 | } |
| 137 | Ok(values) |
| 138 | })?; |
| 139 | |
| 140 | let mut result_rows = Vec::new(); |
| 141 | for row_result in rows { |
| 142 | result_rows.push(row_result?); |
| 143 | } |
| 144 | |
| 145 | let rows_affected = result_rows.len(); |
| 146 | Ok(DbResponse { |
| 147 | columns: column_names, |
| 148 | rows: result_rows, |
| 149 | rows_affected, |
| 150 | }) |
| 151 | } |
| 152 | |
| 153 | /// Get pool statistics for monitoring |
| 154 | pub fn pool_stats(&self) -> PoolStats { |
no test coverage detected