Should be all the database functions I need

[?]
Jan 14, 2022, 12:48 AM
LLFG625ISXV7P2LUOFUMFIM5V5RJDKWCL47XX43X2CGILVAUQPVQC

Dependencies

  • [2] AVLXUT3R Make the boxed errors Send
  • [3] G5YNDTPH Cargo clippy
  • [4] LPVC545K Get the scraper part of this program working
  • [5] 5Y7ZXB53 Start picker UI
  • [6] AV73DYWQ Initial functions for using sqlite in async environment
  • [7] RNW6D777 Minor tidy
  • [8] YCWYAX6K Functions for scraping names integrated enough to test (they don't work yet)
  • [9] KUANIPWF Add function for adding name to database
  • [*] HMOBTVJ4 Initialize crate and add expected dependencies

Change contents

  • replacement in src/pick.rs at line 7
    [4.138][4.138:160]()
    QueueableCommand,
    [4.138]
    [4.160]
    ExecutableCommand, QueueableCommand,
  • replacement in src/pick.rs at line 11
    [4.278][4.278:348]()
    pub async fn pick(db: AsyncConnection, count: u16) -> DynResult<()> {
    [4.278]
    [4.348]
    pub async fn pick(db: &AsyncConnection, count: u16) -> DynResult<()> {
    let mut stderr = std::io::stderr();
    stderr.execute(cursor::Hide)?;
    let (mut input, done) = events();
    stderr.execute(cursor::Show)?;
  • edit in src/names_database.rs at line 18
    [4.523]
    [4.523]
    )?;
    conn.execute(
    "CREATE INDEX IF NOT EXISTS prefs_index ON preferences(better,worse)",
    )?;
    conn.execute(
    "CREATE INDEX IF NOT EXISTS prefs_better ON preferences(better)",
  • edit in src/names_database.rs at line 25
    [4.531]
    [4.531]
    conn.execute(
    "CREATE INDEX IF NOT EXISTS prefs_worse ON preferences(worse)",
    )?;
  • replacement in src/names_database.rs at line 31
    [4.545][4.0:74]()
    type DBFunction = Box<dyn for<'a> FnOnce(&'a sqlite::Connection) + Send>;
    [4.545]
    [4.646]
    type DBFunction =
    Box<dyn for<'a> FnOnce(&'a sqlite::Connection) + Send + Sync + 'static>;
  • edit in src/names_database.rs at line 34
    [4.647]
    [4.75]
    #[derive(Clone)]
  • replacement in src/names_database.rs at line 55
    [4.171][2.51:118](),[2.118][4.286:305](),[4.286][4.286:305]()
    pub async fn add_name(&self, name: String) -> DynResult<i64> {
    match self
    [4.171]
    [4.305]
    pub async fn add_name(&self, name: String) -> DynResult<(i64, bool)> {
    Ok(self
  • replacement in src/names_database.rs at line 61
    [4.496][4.496:531]()
    stmnt.next().ok();
    [4.496]
    [4.531]
    let is_new = stmnt.next().is_ok();
  • replacement in src/names_database.rs at line 66
    [4.740][4.740:809]()
    sqlite::State::Row => Ok(stmnt.read::<i64>(0)?),
    [4.740]
    [4.809]
    sqlite::State::Row => Ok((stmnt.read::<i64>(0)?, is_new)),
  • edit in src/names_database.rs at line 73
    [4.1063]
    [4.1063]
    }
    })
    .await??)
    }
    pub async fn compare(
    &self,
    a: i64,
    b: i64,
    ) -> DynResult<Option<std::cmp::Ordering>> {
    if a == b {
    return Ok(Some(std::cmp::Ordering::Equal));
    }
    Ok(self.post(move |conn| -> DynResult<Option<std::cmp::Ordering>> {
    let mut stmnt = conn.prepare("SELECT better, worse FROM preferences WHERE (better = ? AND worse = ?) OR (better = ? AND worse = ?)")?;
    stmnt.bind::<i64>(1,a)?;
    stmnt.bind::<i64>(2,b)?;
    stmnt.bind::<i64>(3,b)?;
    stmnt.bind::<i64>(4,a)?;
    match stmnt.next()? {
    sqlite::State::Done => Ok(None),
    sqlite::State::Row => {
    let better = stmnt.read::<i64>(0)?;
    let worse = stmnt.read::<i64>(1)?;
    if better == a && worse == b {
    Ok(Some(std::cmp::Ordering::Greater))
    } else if better == b && worse == a {
    Ok(Some(std::cmp::Ordering::Less))
    } else {
    Ok(Some(std::cmp::Ordering::Equal))
    }
    }
    }
    }).await??)
    }
    pub async fn list_names(&self) -> DynResult<Vec<(String, i64)>> {
    match self
    .post(|conn| {
    let mut stmnt =
    conn.prepare("SELECT name, rowid FROM names")?;
    let mut rows = Vec::new();
    while let sqlite::State::Row = stmnt.next()? {
    rows.push((
    stmnt.read::<String>(0)?,
    stmnt.read::<i64>(1)?,
    ));
  • edit in src/names_database.rs at line 121
    [4.1081]
    [4.1081]
    Ok(rows)
  • replacement in src/names_database.rs at line 126
    [4.1155][2.119:182]()
    Ok(Err(e)) => Err(Box::new(e) as crate::DynError),
    [4.1155]
    [4.1229]
    Ok(Err(e)) => Err(e),
  • edit in src/names_database.rs at line 128
    [4.1261]
    [4.1261]
    }
    }
    async fn insert_preference(
    &self,
    better: i64,
    worse: i64,
    ) -> DynResult<()> {
    self.insert_one_preference(better, worse).await?;
    self.make_transitive().await
    }
    async fn insert_one_preference(
    &self,
    better: i64,
    worse: i64,
    ) -> DynResult<()> {
    self.post(move |db| -> DynResult<_> {
    let mut stmnt = db.prepare(
    "INSERT INTO preferences(better, worse) VALUES(?, ?)",
    )?;
    stmnt.bind::<i64>(1, better)?;
    stmnt.bind::<i64>(2, worse)?;
    stmnt.next()?;
    Ok(())
    })
    .await?
    }
    pub async fn make_transitive(&self) -> DynResult<()> {
    loop {
    let todo = self
    .post(|db| -> DynResult<_> {
    let mut stmnt = db.prepare(
    "SELECT a.better, b.worse
    FROM preferences AS a
    INNER JOIN preferences as b ON a.worse = b.better
    WHERE NOT EXISTS (
    SELECT rowid FROM preferences AS x
    WHERE x.better = a.better
    AND x.worse = b.worse
    )
    ",
    )?;
    let mut rows = Vec::new();
    while let sqlite::State::Row = stmnt.next()? {
    rows.push((
    stmnt.read::<i64>(0)?,
    stmnt.read::<i64>(1)?,
    ));
    }
    Ok(rows)
    })
    .await??;
    if todo.is_empty() {
    return Ok(());
    } else {
    let handles: Vec<_> = todo
    .into_iter()
    .map(|(better, worse)| {
    let target = self.clone();
    tokio::spawn(async move {
    target.insert_one_preference(better, worse).await
    })
    })
    .collect();
    for handle in handles {
    handle.await??;
    }
    }
  • replacement in src/names_database.rs at line 202
    [4.1400][4.1400:1462]()
    F: FnOnce(&sqlite::Connection) -> U + Send + 'static,
    [4.1400]
    [4.1462]
    F: FnOnce(&sqlite::Connection) -> U + Send,
  • edit in src/names_database.rs at line 209
    [4.1645]
    [4.1645]
    let h = move |conn: &sqlite::Connection| {
    sc.send(cb(conn)).unwrap_or(());
    };
  • replacement in src/names_database.rs at line 213
    [4.1660][4.1660:1771]()
    .send(Box::new(move |conn: &sqlite::Connection| {
    sc.send(cb(conn)).unwrap_or(());
    [4.1660]
    [4.1771]
    .send(unsafe {
    std::mem::transmute::<_, DBFunction>(Box::new(h)
    as Box<dyn for<'a> FnOnce(&'a sqlite::Connection) + Send>)
  • edit in src/names_database.rs at line 217
    [4.1786][4.1786:1861]()
    as Box<dyn for<'a> FnOnce(&'a sqlite::Connection) + Send>)
  • replacement in src/main.rs at line 47
    [4.779][3.129:168]()
    Self::Pick { count } => {}
    [4.779]
    [4.1643]
    Self::Pick { count } => {
    pick::pick(db, *count).await?;
    }