I'm trying to create a db connection, then pass it to a data gatherer struct, which would gather then use the conn to save the data. It seems I ended up in a complex situation of mutable borrowing and lifetime issues, which I can't find my way out. I created a small example -- I'm hoping someone can make this sense and compile for me:
use rusqlite::{named_params, Connection, Result, ToSql, Transaction};
fn main() -> Result<()> {
let sqlite = Connection::open_in_memory()?;
let dm = DataManager::new(sqlite);
dm.save_data();
Ok(())
}
struct DataManager {
db_conn: Connection
}
impl DataManager {
pub fn new(conn: Connection) -> Self {
DataManager { db_conn: conn }
}
fn save_data(&self) {
let data = 20; //get data
self.save_with_transaction(data, self.db_conn).unwrap();
}
fn save_with_transaction(&self, data: i32, conn: &mut Connection) -> Result<()> {
let tx = conn.transaction()?;
self.do_transaction(data, &tx)?;
tx.commit();
Ok(())
}
fn do_transaction<'a>(&self, data: i32, tx: &Transaction<'a>) -> Result<()> {
let mut stmt = tx.prepare("INSERT INTO data (datapoint) VALUES (:datapoint)")?;
let params: &[(&str, &dyn ToSql)] = named_params! {":datapoint": data};
stmt.execute(params,)?;
Ok(())
}
}
Currently it fails with "cannot borrow self.db_conn
as mutable because it is also borrowed as immutable" on self.save_with_transaction(data, self.db_conn).unwrap();
which I understand, but cannot fix. I tried to make the field mutable:
use rusqlite::{named_params, Connection, Result, ToSql, Transaction};
fn main() -> Result<()> {
let mut sqlite = Connection::open_in_memory()?;
let mut dm = DataManager::new(&mut sqlite);
dm.save_data();
Ok(())
}
struct DataManager<'a> {
db_conn: &'a mut Connection
}
impl DataManager<'_> {
pub fn new(conn: &mut Connection) -> DataManager<'_> {
DataManager { db_conn: conn }
}
fn save_data(&mut self) {
let data = 20; //get data
self.save_with_transaction(data, self.db_conn).unwrap();
}
fn save_with_transaction(&self, data: i32, conn: &mut Connection) -> Result<()> {
let tx = conn.transaction()?;
self.do_transaction(data, &tx)?;
tx.commit();
Ok(())
}
fn do_transaction<'a>(&self, data: i32, tx: &Transaction<'a>) -> Result<()> {
let mut stmt = tx.prepare("INSERT INTO data (datapoint) VALUES (:datapoint)")?;
let params: &[(&str, &dyn ToSql)] = named_params! {":datapoint": data};
stmt.execute(params,)?;
Ok(())
}
}
but then I ended up with mutable and immutable borrow happening on the same line.
I'd appreciate any help from the experts.