]> Untitled Git - lemmy.git/blob - crates/db_views_actor/src/person_mention_view.rs
Merge branch 'main' into federated-moderation
[lemmy.git] / crates / db_views_actor / src / person_mention_view.rs
1 use diesel::{result::Error, *};
2 use lemmy_db_queries::{
3   aggregates::comment_aggregates::CommentAggregates,
4   functions::hot_rank,
5   limit_and_offset,
6   MaybeOptional,
7   SortType,
8   ToSafe,
9   ViewToVec,
10 };
11 use lemmy_db_schema::{
12   schema::{
13     comment,
14     comment_aggregates,
15     comment_like,
16     comment_saved,
17     community,
18     community_follower,
19     community_person_ban,
20     person,
21     person_alias_1,
22     person_mention,
23     post,
24   },
25   source::{
26     comment::{Comment, CommentSaved},
27     community::{Community, CommunityFollower, CommunityPersonBan, CommunitySafe},
28     person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
29     person_mention::PersonMention,
30     post::Post,
31   },
32   PersonId,
33   PersonMentionId,
34 };
35 use serde::Serialize;
36
37 #[derive(Debug, PartialEq, Serialize, Clone)]
38 pub struct PersonMentionView {
39   pub person_mention: PersonMention,
40   pub comment: Comment,
41   pub creator: PersonSafe,
42   pub post: Post,
43   pub community: CommunitySafe,
44   pub recipient: PersonSafeAlias1,
45   pub counts: CommentAggregates,
46   pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan
47   pub subscribed: bool,                    // Left join to CommunityFollower
48   pub saved: bool,                         // Left join to CommentSaved
49   pub my_vote: Option<i16>,                // Left join to CommentLike
50 }
51
52 type PersonMentionViewTuple = (
53   PersonMention,
54   Comment,
55   PersonSafe,
56   Post,
57   CommunitySafe,
58   PersonSafeAlias1,
59   CommentAggregates,
60   Option<CommunityPersonBan>,
61   Option<CommunityFollower>,
62   Option<CommentSaved>,
63   Option<i16>,
64 );
65
66 impl PersonMentionView {
67   pub fn read(
68     conn: &PgConnection,
69     person_mention_id: PersonMentionId,
70     my_person_id: Option<PersonId>,
71   ) -> Result<Self, Error> {
72     // The left join below will return None in this case
73     let person_id_join = my_person_id.unwrap_or(PersonId(-1));
74
75     let (
76       person_mention,
77       comment,
78       creator,
79       post,
80       community,
81       recipient,
82       counts,
83       creator_banned_from_community,
84       subscribed,
85       saved,
86       my_vote,
87     ) = person_mention::table
88       .find(person_mention_id)
89       .inner_join(comment::table)
90       .inner_join(person::table.on(comment::creator_id.eq(person::id)))
91       .inner_join(post::table.on(comment::post_id.eq(post::id)))
92       .inner_join(community::table.on(post::community_id.eq(community::id)))
93       .inner_join(person_alias_1::table)
94       .inner_join(comment_aggregates::table.on(comment::id.eq(comment_aggregates::comment_id)))
95       .left_join(
96         community_person_ban::table.on(
97           community::id
98             .eq(community_person_ban::community_id)
99             .and(community_person_ban::person_id.eq(comment::creator_id)),
100         ),
101       )
102       .left_join(
103         community_follower::table.on(
104           post::community_id
105             .eq(community_follower::community_id)
106             .and(community_follower::person_id.eq(person_id_join)),
107         ),
108       )
109       .left_join(
110         comment_saved::table.on(
111           comment::id
112             .eq(comment_saved::comment_id)
113             .and(comment_saved::person_id.eq(person_id_join)),
114         ),
115       )
116       .left_join(
117         comment_like::table.on(
118           comment::id
119             .eq(comment_like::comment_id)
120             .and(comment_like::person_id.eq(person_id_join)),
121         ),
122       )
123       .select((
124         person_mention::all_columns,
125         comment::all_columns,
126         Person::safe_columns_tuple(),
127         post::all_columns,
128         Community::safe_columns_tuple(),
129         PersonAlias1::safe_columns_tuple(),
130         comment_aggregates::all_columns,
131         community_person_ban::all_columns.nullable(),
132         community_follower::all_columns.nullable(),
133         comment_saved::all_columns.nullable(),
134         comment_like::score.nullable(),
135       ))
136       .first::<PersonMentionViewTuple>(conn)?;
137
138     Ok(PersonMentionView {
139       person_mention,
140       comment,
141       creator,
142       post,
143       community,
144       recipient,
145       counts,
146       creator_banned_from_community: creator_banned_from_community.is_some(),
147       subscribed: subscribed.is_some(),
148       saved: saved.is_some(),
149       my_vote,
150     })
151   }
152 }
153
154 pub struct PersonMentionQueryBuilder<'a> {
155   conn: &'a PgConnection,
156   my_person_id: Option<PersonId>,
157   recipient_id: Option<PersonId>,
158   sort: &'a SortType,
159   unread_only: bool,
160   page: Option<i64>,
161   limit: Option<i64>,
162 }
163
164 impl<'a> PersonMentionQueryBuilder<'a> {
165   pub fn create(conn: &'a PgConnection) -> Self {
166     PersonMentionQueryBuilder {
167       conn,
168       my_person_id: None,
169       recipient_id: None,
170       sort: &SortType::New,
171       unread_only: false,
172       page: None,
173       limit: None,
174     }
175   }
176
177   pub fn sort(mut self, sort: &'a SortType) -> Self {
178     self.sort = sort;
179     self
180   }
181
182   pub fn unread_only(mut self, unread_only: bool) -> Self {
183     self.unread_only = unread_only;
184     self
185   }
186
187   pub fn recipient_id<T: MaybeOptional<PersonId>>(mut self, recipient_id: T) -> Self {
188     self.recipient_id = recipient_id.get_optional();
189     self
190   }
191
192   pub fn my_person_id<T: MaybeOptional<PersonId>>(mut self, my_person_id: T) -> Self {
193     self.my_person_id = my_person_id.get_optional();
194     self
195   }
196
197   pub fn page<T: MaybeOptional<i64>>(mut self, page: T) -> Self {
198     self.page = page.get_optional();
199     self
200   }
201
202   pub fn limit<T: MaybeOptional<i64>>(mut self, limit: T) -> Self {
203     self.limit = limit.get_optional();
204     self
205   }
206
207   pub fn list(self) -> Result<Vec<PersonMentionView>, Error> {
208     use diesel::dsl::*;
209
210     // The left join below will return None in this case
211     let person_id_join = self.my_person_id.unwrap_or(PersonId(-1));
212
213     let mut query = person_mention::table
214       .inner_join(comment::table)
215       .inner_join(person::table.on(comment::creator_id.eq(person::id)))
216       .inner_join(post::table.on(comment::post_id.eq(post::id)))
217       .inner_join(community::table.on(post::community_id.eq(community::id)))
218       .inner_join(person_alias_1::table)
219       .inner_join(comment_aggregates::table.on(comment::id.eq(comment_aggregates::comment_id)))
220       .left_join(
221         community_person_ban::table.on(
222           community::id
223             .eq(community_person_ban::community_id)
224             .and(community_person_ban::person_id.eq(comment::creator_id)),
225         ),
226       )
227       .left_join(
228         community_follower::table.on(
229           post::community_id
230             .eq(community_follower::community_id)
231             .and(community_follower::person_id.eq(person_id_join)),
232         ),
233       )
234       .left_join(
235         comment_saved::table.on(
236           comment::id
237             .eq(comment_saved::comment_id)
238             .and(comment_saved::person_id.eq(person_id_join)),
239         ),
240       )
241       .left_join(
242         comment_like::table.on(
243           comment::id
244             .eq(comment_like::comment_id)
245             .and(comment_like::person_id.eq(person_id_join)),
246         ),
247       )
248       .select((
249         person_mention::all_columns,
250         comment::all_columns,
251         Person::safe_columns_tuple(),
252         post::all_columns,
253         Community::safe_columns_tuple(),
254         PersonAlias1::safe_columns_tuple(),
255         comment_aggregates::all_columns,
256         community_person_ban::all_columns.nullable(),
257         community_follower::all_columns.nullable(),
258         comment_saved::all_columns.nullable(),
259         comment_like::score.nullable(),
260       ))
261       .into_boxed();
262
263     if let Some(recipient_id) = self.recipient_id {
264       query = query.filter(person_mention::recipient_id.eq(recipient_id));
265     }
266
267     if self.unread_only {
268       query = query.filter(person_mention::read.eq(false));
269     }
270
271     query = match self.sort {
272       SortType::Hot | SortType::Active => query
273         .order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc())
274         .then_order_by(comment_aggregates::published.desc()),
275       SortType::New | SortType::MostComments | SortType::NewComments => {
276         query.order_by(comment::published.desc())
277       }
278       SortType::TopAll => query.order_by(comment_aggregates::score.desc()),
279       SortType::TopYear => query
280         .filter(comment::published.gt(now - 1.years()))
281         .order_by(comment_aggregates::score.desc()),
282       SortType::TopMonth => query
283         .filter(comment::published.gt(now - 1.months()))
284         .order_by(comment_aggregates::score.desc()),
285       SortType::TopWeek => query
286         .filter(comment::published.gt(now - 1.weeks()))
287         .order_by(comment_aggregates::score.desc()),
288       SortType::TopDay => query
289         .filter(comment::published.gt(now - 1.days()))
290         .order_by(comment_aggregates::score.desc()),
291     };
292
293     let (limit, offset) = limit_and_offset(self.page, self.limit);
294
295     let res = query
296       .limit(limit)
297       .offset(offset)
298       .load::<PersonMentionViewTuple>(self.conn)?;
299
300     Ok(PersonMentionView::from_tuple_to_vec(res))
301   }
302 }
303
304 impl ViewToVec for PersonMentionView {
305   type DbTuple = PersonMentionViewTuple;
306   fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
307     items
308       .iter()
309       .map(|a| Self {
310         person_mention: a.0.to_owned(),
311         comment: a.1.to_owned(),
312         creator: a.2.to_owned(),
313         post: a.3.to_owned(),
314         community: a.4.to_owned(),
315         recipient: a.5.to_owned(),
316         counts: a.6.to_owned(),
317         creator_banned_from_community: a.7.is_some(),
318         subscribed: a.8.is_some(),
319         saved: a.9.is_some(),
320         my_vote: a.10,
321       })
322       .collect::<Vec<Self>>()
323   }
324 }