Starting to work on community view, 2
This commit is contained in:
parent
88d7b0a83c
commit
efdcbc44c4
7 changed files with 143 additions and 16 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
21
lemmy_db/src/aggregates/community_aggregates.rs
Normal file
21
lemmy_db/src/aggregates/community_aggregates.rs
Normal 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
|
|
@ -1,2 +1,3 @@
|
||||||
|
pub mod community_aggregates;
|
||||||
pub mod site_aggregates;
|
pub mod site_aggregates;
|
||||||
pub mod user_aggregates;
|
pub mod user_aggregates;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue