Starting to work on community view, 2

This commit is contained in:
Dessalines 2020-12-04 16:35:46 -05:00
parent 88d7b0a83c
commit efdcbc44c4
7 changed files with 143 additions and 16 deletions

View file

@ -36,6 +36,7 @@
- [Rust docker build](https://shaneutt.com/blog/rust-fast-small-docker-image-builds/) - [Rust docker build](https://shaneutt.com/blog/rust-fast-small-docker-image-builds/)
- [Zurb mentions](https://github.com/zurb/tribute) - [Zurb mentions](https://github.com/zurb/tribute)
- [TippyJS](https://github.com/atomiks/tippyjs) - [TippyJS](https://github.com/atomiks/tippyjs)
- [SQL function indexes](https://sorentwo.com/2013/12/30/let-postgres-do-the-work.html)
## Activitypub guides ## Activitypub guides

View file

@ -0,0 +1,21 @@
use crate::schema::community_aggregates;
use diesel::{result::Error, *};
use serde::Serialize;
#[derive(Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Clone)]
#[table_name = "community_aggregates"]
pub struct CommunityAggregates {
pub id: i32,
pub community_id: i32,
pub subscribers: i64,
pub posts: i64,
pub counts: i64,
}
impl CommunityAggregates {
pub fn read(conn: &PgConnection, id: i32) -> Result<Self, Error> {
community_aggregates::table.find(id).first::<Self>(conn)
}
}
// TODO add unit tests, to make sure triggers are working

View file

@ -1,2 +1,3 @@
pub mod community_aggregates;
pub mod site_aggregates; pub mod site_aggregates;
pub mod user_aggregates; pub mod user_aggregates;

View file

@ -127,6 +127,16 @@ table! {
} }
} }
table! {
community_aggregates (id) {
id -> Int4,
community_id -> Int4,
subscribers -> Int8,
posts -> Int8,
comments -> Int8,
}
}
table! { table! {
community_aggregates_fast (id) { community_aggregates_fast (id) {
id -> Int4, id -> Int4,
@ -544,6 +554,7 @@ joinable!(comment_saved -> comment (comment_id));
joinable!(comment_saved -> user_ (user_id)); joinable!(comment_saved -> user_ (user_id));
joinable!(community -> category (category_id)); joinable!(community -> category (category_id));
joinable!(community -> user_ (creator_id)); joinable!(community -> user_ (creator_id));
joinable!(community_aggregates -> community (community_id));
joinable!(community_follower -> community (community_id)); joinable!(community_follower -> community (community_id));
joinable!(community_follower -> user_ (user_id)); joinable!(community_follower -> user_ (user_id));
joinable!(community_moderator -> community (community_id)); joinable!(community_moderator -> community (community_id));
@ -587,6 +598,7 @@ allow_tables_to_appear_in_same_query!(
comment_report, comment_report,
comment_saved, comment_saved,
community, community,
community_aggregates,
community_aggregates_fast, community_aggregates_fast,
community_follower, community_follower,
community_moderator, community_moderator,

View file

@ -1,7 +1,8 @@
use crate::{ use crate::{
aggregates::community_aggregates::CommunityAggregates,
category::Category, category::Category,
community::{Community, CommunityFollower}, community::{Community, CommunityFollower},
schema::{category, community, community_follower, user_}, schema::{category, community, community_aggregates, community_follower, user_},
user::{UserSafe, User_}, user::{UserSafe, User_},
}; };
use diesel::{result::Error, *}; use diesel::{result::Error, *};
@ -13,21 +14,9 @@ pub struct CommunityView {
pub creator: UserSafe, pub creator: UserSafe,
pub category: Category, pub category: Category,
pub subscribed: bool, pub subscribed: bool,
pub counts: CommunityAggregates,
} }
// creator_actor_id -> Text,
// creator_local -> Bool,
// creator_name -> Varchar,
// creator_preferred_username -> Nullable<Varchar>,
// creator_avatar -> Nullable<Text>,
// category_name -> Varchar,
// number_of_subscribers -> BigInt,
// number_of_posts -> BigInt,
// number_of_comments -> BigInt,
// hot_rank -> Int4,
// user_id -> Nullable<Int4>,
// subscribed -> Nullable<Bool>,
impl CommunityView { impl CommunityView {
pub fn read( pub fn read(
conn: &PgConnection, conn: &PgConnection,
@ -45,17 +34,19 @@ impl CommunityView {
None => false, None => false,
}; };
let (community, creator, category) = community::table let (community, creator, category, counts) = community::table
.find(community_id) .find(community_id)
.inner_join(user_::table) .inner_join(user_::table)
.inner_join(category::table) .inner_join(category::table)
.first::<(Community, User_, Category)>(conn)?; .inner_join(community_aggregates::table)
.first::<(Community, User_, Category, CommunityAggregates)>(conn)?;
Ok(CommunityView { Ok(CommunityView {
community, community,
creator: creator.to_safe(), creator: creator.to_safe(),
category, category,
subscribed, subscribed,
counts,
}) })
} }
} }

View file

@ -0,0 +1,9 @@
-- community aggregates
drop table community_aggregates;
drop trigger community_aggregates_post_count on post;
drop trigger community_aggregates_comment_count on comment;
drop trigger community_aggregates_subscriber_count on community_follower;
drop function
community_aggregates_post_count,
community_aggregates_comment_count,
community_aggregates_subscriber_count;

View file

@ -0,0 +1,92 @@
-- Add community aggregates
create table community_aggregates (
id serial primary key,
community_id int references community on update cascade on delete cascade not null,
subscribers bigint not null,
posts bigint not null,
comments bigint not null,
unique (community_id)
);
insert into community_aggregates (community_id, subscribers, posts, comments)
select
c.id,
coalesce(cf.subs, 0::bigint) as subscribers,
coalesce(cd.posts, 0::bigint) as posts,
coalesce(cd.comments, 0::bigint) as comments
from community c
left join (
select
p.community_id,
count(distinct p.id) as posts,
count(distinct ct.id) as comments
from post p
left join comment ct on p.id = ct.post_id
group by p.community_id
) cd on cd.community_id = c.id
left join (
select
community_follower.community_id,
count(*) as subs
from community_follower
group by community_follower.community_id
) cf on cf.community_id = c.id;
-- Add community aggregate triggers
-- post count
create function community_aggregates_post_count()
returns trigger language plpgsql
as $$
begin
IF (TG_OP = 'INSERT') THEN
update community_aggregates
set posts = posts + 1 where community_id = NEW.community_id;
ELSIF (TG_OP = 'DELETE') THEN
update community_aggregates
set posts = posts - 1 where community_id = OLD.community_id;
END IF;
return null;
end $$;
create trigger community_aggregates_post_count
after insert or delete on post
execute procedure community_aggregates_post_count();
-- comment count
create function community_aggregates_comment_count()
returns trigger language plpgsql
as $$
begin
IF (TG_OP = 'INSERT') THEN
update community_aggregates
set comments = comments + 1 where community_id = NEW.community_id;
ELSIF (TG_OP = 'DELETE') THEN
update community_aggregates
set comments = comments - 1 where community_id = OLD.community_id;
END IF;
return null;
end $$;
create trigger community_aggregates_comment_count
after insert or delete on comment
execute procedure community_aggregates_comment_count();
-- subscriber count
create function community_aggregates_subscriber_count()
returns trigger language plpgsql
as $$
begin
IF (TG_OP = 'INSERT') THEN
update community_aggregates
set subscribers = subscribers + 1 where community_id = NEW.community_id;
ELSIF (TG_OP = 'DELETE') THEN
update community_aggregates
set subscribers = subscribers - 1 where community_id = OLD.community_id;
END IF;
return null;
end $$;
create trigger community_aggregates_subscriber_count
after insert or delete on community_follower
execute procedure community_aggregates_subscriber_count();