rss-tool/src/db.rs

187 lines
5.1 KiB
Rust
Raw Normal View History

use std::path::PathBuf;
use chrono::FixedOffset;
use rusqlite::{ Connection, Result};
use super::files::*;
use super::net::*;
use chrono::Utc; //Maybe use a different time?
use chrono::DateTime;
/*
Cache is the in-memory database
Any changes/updates are written to file database
*/
struct Item {
title: String,
content: Option<String>,
}
const DB_LOCATION: &str = "rsscar.db";
fn get_db_path() -> PathBuf {
get_data_directory().join(DB_LOCATION)
}
const FEEDS_TABLE_CREATE: &str = "CREATE TABLE IF NOT EXISTS 'feeds' (
'feedID' INTEGER NOT NULL,
'title' TEXT NOT NULL,
'description' TEXT,
'icon' BLOB,
'url' text not null unique on conflict replace,
'subscribed' INTEGER NOT NULL default 0,
'last_updated' TEXT ,
PRIMARY KEY('feedID')
);";
const FEEDS_INDEX_CREATE: &str = "CREATE INDEX IF NOT EXISTS 'subscribed_feeds_idx' ON 'feeds' (
'feedID' ASC
) WHERE 'subscribed' = 1;";
2025-05-28 14:53:05 -04:00
/* */
const ITEMS_TABLE_CREATE: &str = "CREATE TABLE IF NOT EXISTS 'items' (
'itemID' INTEGER NOT NULL,
'title' TEXT NOT NULL,
'icon' BLOB,
'url' text not null unique on conflict replace,
'description' TEXT,
'content' TEXT,
'read' INTEGER DEFAULT 0,
PRIMARY KEY('itemID')
);";
const ITEMS_INDEX_CREATE: &str = "CREATE INDEX IF NOT EXISTS 'items_idx' on 'items'('itemID' ASC);";
pub fn initialize() {
let path = get_db_path();
println!("Database at {} initialized", path.as_os_str().display());
let conn = Connection::open(path).unwrap();
conn.execute(FEEDS_TABLE_CREATE, []).unwrap();
conn.execute(FEEDS_INDEX_CREATE, []).unwrap();
conn.execute(ITEMS_TABLE_CREATE, []).unwrap();
conn.execute(ITEMS_INDEX_CREATE, []).unwrap();
conn.close().unwrap();
println!("Database Initialized.")
}
pub fn add_feed(url: &str) {
let conn = Connection::open(get_db_path()).unwrap();
let feed = load_rss(url).unwrap();
let new_feed = feed.clone();
let time = Utc::now().to_rfc2822();
conn.execute(
"insert into feeds(title,url,description,last_updated) values(?1,?2,?3,?4)",
[feed.title, url.to_owned(), feed.description, time],
)
.unwrap();
conn.close().unwrap();
store_items(new_feed);
}
pub fn store_items(feed: rss::Channel) {
let conn = Connection::open(get_db_path()).unwrap();
feed.items.iter().for_each(|i: &rss::Item| {
conn.execute(
"insert into items(url,title,description,content) values(?1,?2,?3,?4)",
[
i.link.clone(),
i.title.clone(),
i.description.clone(),
i.content.clone(),
],
)
.unwrap();
});
conn.close().unwrap();
}
pub fn return_item() -> String {
let conn = Connection::open(get_db_path()).unwrap();
let item = conn
.query_row(
"select title,content from items where rowid=?1",
[],
|row| {
Ok(Item {
title: row.get(0).unwrap(),
content: row.get(1).unwrap(),
})
},
)
.unwrap();
match item.content {
Some(content) => content,
None => panic!(),
}
}
pub struct Feed {
pub feed_id: u8,
pub title: String,
pub description: Option<String>,
pub icon: Option<String>,
pub url: String,
pub subscribed: bool,
pub last_updated: Option<DateTime<Utc>>,
}
fn time_string_conversion(str: String) -> Option<DateTime<Utc>>{
match DateTime::parse_from_rfc2822(&str) {
Ok(dt) => {Some(dt.to_utc())},
Err(_) => {None}
}
}
pub fn get_feeds() -> Vec<Feed> {
let conn = Connection::open(get_db_path()).unwrap();
let mut stmt = conn.prepare("select feedID,title,description,icon,url,subscribed,last_updated from feeds").unwrap();
let rows: Result<Vec<Feed>> = stmt
.query_map([], |row| {
Ok(Feed {
feed_id: row.get(0).unwrap(),
title: row.get(1).unwrap(),
description: row.get(2).unwrap(),
icon: row.get(3).unwrap(),
url: row.get(4).unwrap(),
subscribed: row.get::<_,bool>(5).unwrap(),
last_updated:time_string_conversion(row.get(6).unwrap()),
})
}).unwrap().collect();
match rows {
Ok(r) => {
println!("Feed found\n{}",r[0].title);
r
}
Err(e) => {panic!()}
}
}
struct ReturnedFeedURLs {
url: String,
}
pub fn update_feeds() {
//get feeds
let conn = Connection::open(get_db_path()).unwrap();
let mut stmt = conn.prepare("select url from feeds").unwrap();
let rows = stmt
.query_map([], |row| {
Ok(ReturnedFeedURLs {
url: row.get(0).unwrap(),
})
})
.unwrap();
let mut urls: Vec<String> = Vec::new();
for feed in rows {
let url = feed.unwrap().url.clone();
urls.push(url);
}
stmt.finalize().unwrap();
conn.close().unwrap();
for u in urls {
store_items(load_rss(&u).unwrap());
}
//for each feed
// insert items into database
//close out
}