So I have this code which uses rusqlite
. And it works fine.
pub struct Database {
conn: Connection,
}
impl Database {
pub fn get(self: &Self, id: Option<u64>, name: Option<&str>) -> Result<Option<Record>, Error> {
let mut stmt = match name {
Some(_) => { self.conn.prepare_cached(Self::STMT_GET_ID_NAME) },
None => { self.conn.prepare_cached(Self::STMT_GET_ID) }
}?;
let mut rows = match name {
Some(name) => { stmt.query(params![id, name]) },
None => { stmt.query(params![id]) }
}?;
let row = rows.next()?;
if let Some(row) = row {
let record = Record {
id: row.get(0)?,
parent: row.get(1)?,
name: row.get(2)?,
record_type: row.get(3)?,
timestamp: row.get(4)?,
created_at: row.get(5)?,
modified_at: row.get(6)?,
size: row.get(7)?,
hash: row.get(8)?,
inode: row.get(9)?
};
Ok(Some(record))
} else {
Ok(None)
}
}
}
The problem I have is that the match
statement is essentially duplicated.
I tried something like this but this won't work.
let (mut stmt, mut rows) = match name {
Some(name) => {
let mut stmt = self.conn.prepare_cached(Self::STMT_GET_ID_NAME)?;
let rows = stmt.query(params![id, name])?;
(stmt, rows)
}
None => {
let mut stmt = self.conn.prepare_cached(Self::STMT_GET_ID)?;
let rows = stmt.query(params![id])?;
(stmt, rows)
}
};
The problem is that the compiler complains about the lifetime of stmt
error[E0597]: `stmt` does not live long enough
error[E0505]: cannot move out of `stmt` because it is borrowed
I really tried a lot of things and try to google furiously. But I'm stuck.
Is there even a way to do this that is not utterly ugly and idiomatic? I feel like this is a really dumb problem, and I'm missing something fundamental here…
The problem is that attempting to "return" both stmt
and rows
from the subexpression moves stmt
and therefore invalidates references held by rows
. To fix this, you can omit the inner stmt
and assign directly to the outer one from your match arms. That way stmt
never moves and the borrow checker is happy, so e.g. this compiles:
let mut stmt;
let mut rows = match name {
Some(name) => {
stmt = self.conn.prepare_cached(Self::STMT_GET_ID_NAME)?;
stmt.query(params![id, name])?
}
None => {
stmt = self.conn.prepare_cached(Self::STMT_GET_ID)?;
stmt.query(params![id])?
}
};