Files
oolatoocs/src/state.rs
2023-11-08 16:12:41 +01:00

230 lines
5.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use log::debug;
use rusqlite::{params, Connection, OptionalExtension};
use std::error::Error;
/// Struct for each query line
#[derive(Debug)]
pub struct TweetToToot {
pub tweet_id: u64,
pub toot_id: u64,
}
/// if None is passed, read the last tweet from DB
/// if a tweet_id is passed, read this particular tweet from DB
pub fn read_state(
conn: &Connection,
s: Option<u64>,
) -> Result<Option<TweetToToot>, Box<dyn Error>> {
debug!("Reading toot_id {:?}", s);
let query: String = match s {
Some(i) => format!("SELECT * FROM tweet_to_toot WHERE toot_id = {i}"),
None => "SELECT * FROM tweet_to_toot ORDER BY toot_id DESC LIMIT 1".to_string(),
};
let mut stmt = conn.prepare(&query)?;
let t = stmt
.query_row([], |row| {
Ok(TweetToToot {
tweet_id: row.get("tweet_id")?,
toot_id: row.get("toot_id")?,
})
})
.optional()?;
Ok(t)
}
/// Writes last treated tweet id and toot id to the db
pub fn write_state(conn: &Connection, t: TweetToToot) -> Result<(), Box<dyn Error>> {
debug!("Write struct {:?}", t);
conn.execute(
"INSERT INTO tweet_to_toot (tweet_id, toot_id) VALUES (?1, ?2)",
params![t.tweet_id, t.toot_id],
)?;
Ok(())
}
/// Initiates the DB from path
pub fn init_db(d: &str) -> Result<(), Box<dyn Error>> {
debug!(
"{}",
format!("Initializing DB for {}", env!("CARGO_PKG_NAME"))
);
let conn = Connection::open(d)?;
conn.execute(
"CREATE TABLE IF NOT EXISTS tweet_to_toot (
tweet_id INTEGER,
toot_id INTEGER PRIMARY KEY
)",
[],
)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::{fs::remove_file, path::Path};
#[test]
fn test_init_db() {
let d = "/tmp/test_init_db.sqlite";
init_db(d).unwrap();
// check that file exist
assert!(Path::new(d).exists());
// open said file
let conn = Connection::open(d).unwrap();
conn.execute("SELECT * from tweet_to_toot;", []).unwrap();
remove_file(d).unwrap();
}
#[test]
fn test_init_init_db() {
// init_db fn should be idempotent so lets test that
let d = "/tmp/test_init_init_db.sqlite";
init_db(d).unwrap();
let conn = Connection::open(d).unwrap();
conn.execute(
"INSERT INTO tweet_to_toot (tweet_id, toot_id)
VALUES
(100, 1001);",
[],
)
.unwrap();
init_db(d).unwrap();
remove_file(d).unwrap();
}
#[test]
fn test_write_state() {
let d = "/tmp/test_write_state.sqlite";
init_db(d).unwrap();
let conn = Connection::open(d).unwrap();
let t_in = TweetToToot {
tweet_id: 123456789,
toot_id: 987654321,
};
write_state(&conn, t_in).unwrap();
let mut stmt = conn.prepare("SELECT * FROM tweet_to_toot;").unwrap();
let t_out = stmt
.query_row([], |row| {
Ok(TweetToToot {
tweet_id: row.get("tweet_id").unwrap(),
toot_id: row.get("toot_id").unwrap(),
})
})
.unwrap();
assert_eq!(t_out.tweet_id, 123456789);
assert_eq!(t_out.toot_id, 987654321);
remove_file(d).unwrap();
}
#[test]
fn test_none_to_tweet_id_read_state() {
let d = "/tmp/test_none_to_tweet_id_read_state.sqlite";
init_db(d).unwrap();
let conn = Connection::open(d).unwrap();
conn.execute(
"INSERT INTO tweet_to_toot (tweet_id, toot_id)
VALUES
(101, 1001),
(102, 1002);",
[],
)
.unwrap();
let t_out = read_state(&conn, None).unwrap().unwrap();
remove_file(d).unwrap();
assert_eq!(t_out.tweet_id, 102);
assert_eq!(t_out.toot_id, 1002);
}
#[test]
fn test_none_to_none_read_state() {
let d = "/tmp/test_none_to_none_read_state.sqlite";
init_db(d).unwrap();
let conn = Connection::open(d).unwrap();
let t_out = read_state(&conn, None).unwrap();
remove_file(d).unwrap();
assert!(t_out.is_none());
}
#[test]
fn test_tweet_id_to_none_read_state() {
let d = "/tmp/test_tweet_id_to_none_read_state.sqlite";
init_db(d).unwrap();
let conn = Connection::open(d).unwrap();
conn.execute(
"INSERT INTO tweet_to_toot (tweet_id, toot_id)
VALUES
(100, 1000);",
[],
)
.unwrap();
let t_out = read_state(&conn, Some(1200)).unwrap();
remove_file(d).unwrap();
assert!(t_out.is_none());
}
#[test]
fn test_tweet_id_to_tweet_id_read_state() {
let d = "/tmp/test_tweet_id_to_tweet_id_read_state.sqlite";
init_db(d).unwrap();
let conn = Connection::open(d).unwrap();
conn.execute(
"INSERT INTO tweet_to_toot (tweet_id, toot_id)
VALUES
(100, 1000);",
[],
)
.unwrap();
let t_out = read_state(&conn, Some(1000)).unwrap().unwrap();
remove_file(d).unwrap();
assert_eq!(t_out.tweet_id, 100);
assert_eq!(t_out.toot_id, 1000);
}
}