diff --git a/koucha/src/db.rs b/koucha/src/db.rs index cea05ac..6914cfa 100644 --- a/koucha/src/db.rs +++ b/koucha/src/db.rs @@ -11,23 +11,15 @@ pub use channel::Channel; mod item; pub use item::Item; -macro_rules! define_key { - ($name:ident) => { - #[derive(PartialEq, Debug, Copy, Clone)] - pub struct $name(i64); - }; - - ($name:ident, $($field:ident),* $(,)?) => { - #[derive(PartialEq, Debug, Copy, Clone)] - pub struct $name { - $($field: i64),* - } - }; +macro_rules! define_id { + ($name:ident) => { + #[derive(PartialEq, Debug, Copy, Clone)] + pub struct $name(i64); + impl From<$name> for i64 { fn from(id: $name) -> Self { id.0 } } + }; } -define_key!(UserKey); -define_key!(FeedKey); -define_key!(FeedChannelKey, feed_id, channel_id); -define_key!(FeedItemKey, feed_id, item_id); -define_key!(ChannelKey); -define_key!(ItemKey); +define_id!(UserId); +define_id!(FeedId); +define_id!(ChannelId); +define_id!(ItemId); diff --git a/koucha/src/db/channel.rs b/koucha/src/db/channel.rs index b79454f..6df59fb 100644 --- a/koucha/src/db/channel.rs +++ b/koucha/src/db/channel.rs @@ -4,7 +4,7 @@ use crate::{ Result, AdapterPool, db::{ - ChannelKey, + ChannelId, Item, FeedChannel, feed_channel::UnparsedFeedChannel, @@ -23,7 +23,7 @@ pub struct UnparsedChannel { impl UnparsedChannel { pub fn parse(self) -> Result { Ok(Channel { - id: ChannelKey(self.id), + id: ChannelId(self.id), title: self.title, link: Url::parse(&self.link)?, description: self.description, @@ -36,7 +36,7 @@ impl UnparsedChannel { } pub struct Channel { - id: ChannelKey, + id: ChannelId, title: String, link: Url, description: Option, @@ -44,7 +44,7 @@ pub struct Channel { } impl Channel { - pub fn id(&self) -> ChannelKey { self.id } + pub fn id(&self) -> ChannelId { self.id } pub fn title(&self) -> &str { &self.title } pub fn link(&self) -> &Url { &self.link } pub fn description(&self) -> Option<&str> { self.description.as_deref() } @@ -59,7 +59,7 @@ impl Channel { channels } - pub async fn get(pool: &AdapterPool, id: ChannelKey) -> Result { + pub async fn get(pool: &AdapterPool, id: ChannelId) -> Result { let channel: Result = sqlx::query_as!( UnparsedChannel, "SELECT id, title, link, description, last_fetched @@ -245,7 +245,10 @@ mod tests { let channel1 = Channel::get_or_create(pool, url_feed.clone()).await.unwrap(); let channel2 = Channel::get_or_create(pool, url_feed).await.unwrap(); - assert_eq!(channel1.id(), channel2.id()); + assert_eq!( + i64::from(channel1.id()), + i64::from(channel2.id()) + ); } #[tokio::test] diff --git a/koucha/src/db/feed.rs b/koucha/src/db/feed.rs index c3c95d1..a769b1b 100644 --- a/koucha/src/db/feed.rs +++ b/koucha/src/db/feed.rs @@ -3,10 +3,10 @@ use crate::{ Result, db::{ Channel, - ChannelKey, - FeedKey, + ChannelId, + FeedId, Item, - UserKey, + UserId, channel::UnparsedChannel, item::UnparsedItem, }, @@ -19,23 +19,23 @@ pub struct UnparsedFeed { impl UnparsedFeed { pub fn parse(self) -> Result { Ok(Feed { - id: FeedKey(self.id), + id: FeedId(self.id), title: self.title, }) } } pub struct Feed { - id: FeedKey, + id: FeedId, title: String, } impl Feed { - pub fn id(&self) -> FeedKey { self.id } + pub fn id(&self) -> FeedId { self.id } pub fn title(&self) -> &str { &self.title } pub async fn get( - pool: &AdapterPool, id: FeedKey + pool: &AdapterPool, id: FeedId ) -> Result { let feed = sqlx::query_as!( UnparsedFeed, @@ -47,21 +47,22 @@ impl Feed { } pub async fn create( - pool: &AdapterPool, user_id: UserKey, title: &str + pool: &AdapterPool, user_id: UserId, title: &str ) -> Result { + let int_id = i64::from(user_id); let new_feed = sqlx::query_as!( UnparsedFeed, "INSERT INTO feeds (user_id, title) VALUES (?, ?) RETURNING id as `id!`, title", - user_id.0, title + int_id, title ).fetch_one(&pool.0).await?.parse(); new_feed } pub async fn update_title( - pool: &AdapterPool, id: FeedKey, new_title: &str + pool: &AdapterPool, id: FeedId, new_title: &str ) -> Result<()> { sqlx::query!( "UPDATE feeds SET title = ? WHERE id = ?", @@ -72,12 +73,13 @@ impl Feed { } pub async fn add_channel( - &self, pool: &AdapterPool, channel_id: ChannelKey + &self, pool: &AdapterPool, channel_id: ChannelId ) -> Result<()> { + let int_channel_id = i64::from(channel_id); sqlx::query!( "INSERT INTO feed_channels (feed_id, channel_id) VALUES (?, ?)", - self.id.0, channel_id.0 + self.id.0, int_channel_id ).execute(&pool.0).await?; Ok(()) diff --git a/koucha/src/db/feed_channel.rs b/koucha/src/db/feed_channel.rs index d736c2d..f8a3870 100644 --- a/koucha/src/db/feed_channel.rs +++ b/koucha/src/db/feed_channel.rs @@ -3,9 +3,9 @@ use crate::{ AdapterPool, db::{ Channel, - ChannelKey, + ChannelId, Feed, - FeedKey, + FeedId, Item, }, score::{ @@ -26,8 +26,8 @@ pub struct UnparsedFeedChannel { impl UnparsedFeedChannel { pub fn parse(self) -> Result { Ok(FeedChannel { - channel_id: ChannelKey(self.channel_id), - feed_id: FeedKey(self.feed_id), + channel_id: ChannelId(self.channel_id), + feed_id: FeedId(self.feed_id), initial_score: Score::new(self.initial_score), gravity: Gravity::new(self.gravity), boost: Boost::new(self.boost), @@ -36,8 +36,8 @@ impl UnparsedFeedChannel { } pub struct FeedChannel { - channel_id: ChannelKey, - feed_id: FeedKey, + channel_id: ChannelId, + feed_id: FeedId, initial_score: Score, gravity: Gravity, boost: Boost, @@ -60,14 +60,15 @@ impl FeedChannel { async fn add_item_at( &self, pool: &AdapterPool, item: &Item, add_at: DateTime ) -> Result<()> { - let int_item_id = item.id().0; + let int_item_id = i64::from(item.id()); + let int_feed_id = i64::from(self.feed_id); let int_initial_score = i64::from(self.initial_score); let string_last_updated = add_at.to_rfc2822(); sqlx::query!( "INSERT OR IGNORE INTO feed_items (feed_id, item_id, score, last_updated) VALUES (?, ?, ?, ?)", - self.feed_id.0, int_item_id, int_initial_score, string_last_updated + int_feed_id, int_item_id, int_initial_score, string_last_updated ).execute(&pool.0).await?; Ok(()) } @@ -80,7 +81,7 @@ mod tests { use crate::{ db::{ Channel, - FeedKey, + FeedId, User }, test_utils::{ @@ -123,7 +124,7 @@ mod tests { let fc = FeedChannel { channel_id: channel.id(), - feed_id: FeedKey(1), // Fake Feed + feed_id: FeedId(1), // Fake Feed initial_score: Score::new(None), gravity: Gravity::new(None), boost: Boost::new(None), @@ -142,7 +143,7 @@ mod tests { let feed = Feed::create(pool, user.id(), "My Feed").await.unwrap(); let fc = FeedChannel { - channel_id: ChannelKey(1), // Fake Channel + channel_id: ChannelId(1), // Fake Channel feed_id: feed.id(), initial_score: Score::new(None), gravity: Gravity::new(None), diff --git a/koucha/src/db/feed_item.rs b/koucha/src/db/feed_item.rs index ba1c29a..052e8a3 100644 --- a/koucha/src/db/feed_item.rs +++ b/koucha/src/db/feed_item.rs @@ -3,11 +3,12 @@ use crate::{ Result, AdapterPool, db::{ - FeedItemKey, + ItemId, + FeedId, }, score::{ TimedScore, - UnparsedTimedScore + UnparsedTimedScore, }, }; @@ -21,10 +22,8 @@ pub struct UnparsedFeedItem { impl UnparsedFeedItem { pub fn parse(self) -> Result { Ok(FeedItem { - key: FeedItemKey { - feed_id: self.feed_id, - item_id: self.item_id, - }, + item_id: ItemId(self.item_id), + feed_id: FeedId(self.feed_id), score: (UnparsedTimedScore { value: self.score, last_updated: DateTime::parse_from_rfc2822(&self.last_updated)? @@ -39,41 +38,19 @@ impl UnparsedFeedItem { } pub struct FeedItem { - key: FeedItemKey, + item_id: ItemId, + feed_id: FeedId, score: TimedScore, } impl FeedItem { - pub fn key(&self) -> FeedItemKey { self.key } - pub fn score(&self) -> TimedScore { self.score.clone() } - - pub async fn archive( - &self, pool: &AdapterPool - ) -> Result<()> { - sqlx::query!( - "UPDATE feed_items - SET archived = ? - WHERE feed_id = ? AND item_id = ?", - true, self.key.feed_id, self.key.item_id - ).execute(&pool.0).await?; - - Ok(()) - } - - pub async fn update_score( - pool: &AdapterPool, key: FeedItemKey, new_score: TimedScore - ) -> Result<()> { - let unparsed_score = UnparsedTimedScore::unparse(new_score); - let last_updated = unparsed_score.last_updated.to_rfc2822(); - let boosted_at = unparsed_score.last_boosted.map(|lb| lb.to_rfc2822()); - - sqlx::query!( - "UPDATE feed_items - SET score = ?, last_updated = ?, boosted_at = ? - WHERE feed_id = ? AND item_id = ?", - unparsed_score.value, last_updated, boosted_at, key.feed_id, key.item_id - ).execute(&pool.0).await?; - - Ok(()) - } + // async fn boost(pool: &AdapterPool, boost: Boost) -> Result<()> { + // self.boost_at(pool, boost, Utc::now()).await + // } + // + // async fn boost_at( + // &self, pool: &AdapterPool, boost: Boost, boost_at: DateTime + // ) -> Result<()> { + // + // } } diff --git a/koucha/src/db/item.rs b/koucha/src/db/item.rs index e3486d4..cb25331 100644 --- a/koucha/src/db/item.rs +++ b/koucha/src/db/item.rs @@ -2,8 +2,8 @@ use crate::{ Result, AdapterPool, db::{ - ChannelKey, - ItemKey, + ChannelId, + ItemId, }, fetch::FetchedRSSItem, }; @@ -22,8 +22,8 @@ pub struct UnparsedItem { impl UnparsedItem { pub fn parse(self) -> Result { Ok(Item { - id: ItemKey(self.id), - channel_id: ChannelKey(self.channel_id), + id: ItemId(self.id), + channel_id: ChannelId(self.channel_id), fetched_at: match self.fetched_at { Some(dt_str) => Some(DateTime::parse_from_rfc2822(&dt_str)? .with_timezone(&Utc)), @@ -38,8 +38,8 @@ impl UnparsedItem { } pub struct Item { - id: ItemKey, - channel_id: ChannelKey, + id: ItemId, + channel_id: ChannelId, #[allow(dead_code)] // TODO: Use for score decay calculations later fetched_at: Option>, @@ -49,15 +49,16 @@ pub struct Item { } impl Item { - pub fn id(&self) -> ItemKey { self.id } - pub fn channel(&self) -> ChannelKey { self.channel_id } + pub fn id(&self) -> ItemId { self.id } + pub fn channel(&self) -> ChannelId { self.channel_id } pub fn title(&self) -> Option<&str> { self.title.as_deref() } pub fn description(&self) -> Option<&str> { self.description.as_deref() } pub fn content(&self) -> Option<&str> { self.content.as_deref() } pub async fn get_or_create( - pool: &AdapterPool, from_channel: ChannelKey, guid: &str + pool: &AdapterPool, from_channel: ChannelId, guid: &str ) -> Result { + let int_channel_id = i64::from(from_channel); let item = sqlx::query_as!( UnparsedItem, @@ -66,7 +67,7 @@ impl Item { ON CONFLICT(channel_id, guid) DO UPDATE SET channel_id = channel_id RETURNING id as `id!`, channel_id, fetched_at, title, description, content", - from_channel.0, guid + int_channel_id, guid ).fetch_one(&pool.0).await?.parse(); item diff --git a/koucha/src/db/user.rs b/koucha/src/db/user.rs index ef7ba51..63f24d8 100644 --- a/koucha/src/db/user.rs +++ b/koucha/src/db/user.rs @@ -2,7 +2,7 @@ use crate::{ Result, AdapterPool, db::{ - UserKey, + UserId, Feed, feed::UnparsedFeed, }, @@ -15,22 +15,22 @@ pub struct UnparsedUser { impl UnparsedUser { pub fn parse(self) -> Result { Ok(User { - id: UserKey(self.id), + id: UserId(self.id), name: self.name }) } } pub struct User { - id: UserKey, + id: UserId, name: String, } impl User { - pub fn id(&self) -> UserKey { self.id } + pub fn id(&self) -> UserId { self.id } pub fn name(&self) -> &str { &self.name } - pub async fn get(pool: &AdapterPool, id: UserKey) -> Result { + pub async fn get(pool: &AdapterPool, id: UserId) -> Result { let user = sqlx::query_as!( UnparsedUser, "SELECT id, name FROM users WHERE id = ?", @@ -58,13 +58,13 @@ impl User { ).fetch_one(&pool.0).await?; Ok(Self { - id: UserKey(result.id), + id: UserId(result.id), name: result.name, }) } pub async fn update_name( - pool: &AdapterPool, id: UserKey, new_name: &str + pool: &AdapterPool, id: UserId, new_name: &str ) -> Result<()> { sqlx::query!( "UPDATE users SET name = ? WHERE id = ?", diff --git a/koucha/src/score.rs b/koucha/src/score.rs index 754ca17..6d6cba2 100644 --- a/koucha/src/score.rs +++ b/koucha/src/score.rs @@ -80,24 +80,8 @@ impl UnparsedTimedScore { }), } } - - pub fn unparse(ts: TimedScore) -> Self { - match ts { - TimedScore::Decaying(ds) => UnparsedTimedScore { - value: ds.value.into(), - last_updated: ds.last_updated, - last_boosted: None, - }, - TimedScore::Boosted(bs) => UnparsedTimedScore { - value: bs.value.into(), - last_updated: bs.boosted_at, - last_boosted: Some(bs.boosted_at), - }, - } - } } -#[derive(Clone)] pub enum TimedScore { Decaying(DecayingScore), Boosted(BoostedScore), @@ -164,13 +148,11 @@ impl TimedScore { } } -#[derive(Clone)] pub struct BoostedScore { value: Score, boosted_at: DateTime, } -#[derive(Clone)] pub struct DecayingScore { value: Score, last_updated: DateTime,