I am learning rust doing a simple app which use an sqlite database. I use the rusqlite
crate for this. To organize my code I have created a database.rs
module where I have implemented a new trait for the Connection
struct. This allow me to hide the database internal from the rest of the code. But I can't figure out how to implement the get_all / iterator thing.
database.rs
:
use anyhow::Result;
use rusqlite::Connection;
pub fn new() -> Result<Connection> {
let db = Connection::open_in_memory()?;
db.execute_batch(
"CREATE TABLE IF NOT EXISTS foobar (
id INTEGER PRIMARY KEY AUTOINCREMENT,
foo TEXT NOT NULL,
bar TEXT NOT NULL,
UNIQUE(foo, bar)
);",
)?;
Ok(db)
}
struct Foobar {
foo: String,
bar: String,
}
pub trait MyApp {
fn get_foobar_id(&self, foo: &str, bar: &str) -> Result<i64>;
fn add_foobar(&self, foo: &str, bar: &str) -> Result<i64>;
fn get_foobar(&self, id: i64) -> Result<Foobar>;
fn get_all_foobar(&self) -> Result< ??? >;
}
impl MyApp for Connection {
fn get_foobar_id(&self, foo: &str, bar: &str) -> Result<i64> {
let id = self.query_row(
"SELECT id FROM foobar WHERE foo = ?1 AND bar = ?2",
[foo, bar],
|row| row.get(0),
)?;
Ok(id)
}
fn add_foobar(&self, foo: &str, bar: &str) -> Result<i64> {
self.execute(
"INSERT OR IGNORE INTO foobar (foo, bar) VALUES (?1, ?2)",
[foo, bar],
)?;
let id = self.get_foobar_id(foo, bar)?;
Ok(id)
}
fn get_foobar(&self, id: i64) -> Result<Foobar> {
let foobar = self.query_row("SELECT foo, bar FROM foobar WHERE id = ?1", [id], |row| {
Ok(Foobar {
foo: row.get(0)?,
bar: row.get(1)?,
})
})?;
Ok(foobar)
}
fn get_all_foobar(&self) -> Result< ??? > {
let mut stmt = self.prepare("SELECT foo, bar FROM foobar")?;
let rows = stmt.query_map([], |row| {
Ok(Foobar {
foo: row.get(0)?,
bar: row.get(1)?,
})
})?;
Ok(rows)
}
}
main.rs
:
use anyhow::Result;
mod database;
fn main() -> Result<()> {
let mut db = crate::database::new()?;
db.add_foobar("foo", "bar")?;
for foobar in db.get_all_foobar()? {
// Do something with foobar
}
Ok(())
}
I have trouble to finish the get_all_foobar
function, especially to find the correct typing for it. How can I do this? Is it the good way to do it? And is this architecture considered best practice?