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