How to wrap iterator from an external module

45 views Asked by At

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?

0

There are 0 answers