1 use super::post_view::post_mview::BoxedQuery;
5 // The faked schema since diesel doesn't do views
10 url -> Nullable<Text>,
11 body -> Nullable<Text>,
16 published -> Timestamp,
17 updated -> Nullable<Timestamp>,
21 banned_from_community -> Bool,
23 creator_name -> Varchar,
24 creator_avatar -> Nullable<Text>,
25 community_name -> Varchar,
26 community_removed -> Bool,
27 community_deleted -> Bool,
28 community_nsfw -> Bool,
29 number_of_comments -> BigInt,
34 user_id -> Nullable<Int4>,
35 my_vote -> Nullable<Int4>,
36 subscribed -> Nullable<Bool>,
37 read -> Nullable<Bool>,
38 saved -> Nullable<Bool>,
43 Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
45 #[table_name = "post_view"]
49 pub url: Option<String>,
50 pub body: Option<String>,
52 pub community_id: i32,
55 pub published: chrono::NaiveDateTime,
56 pub updated: Option<chrono::NaiveDateTime>,
60 pub banned_from_community: bool,
62 pub creator_name: String,
63 pub creator_avatar: Option<String>,
64 pub community_name: String,
65 pub community_removed: bool,
66 pub community_deleted: bool,
67 pub community_nsfw: bool,
68 pub number_of_comments: i64,
73 pub user_id: Option<i32>,
74 pub my_vote: Option<i32>,
75 pub subscribed: Option<bool>,
76 pub read: Option<bool>,
77 pub saved: Option<bool>,
80 // The faked schema since diesel doesn't do views
85 url -> Nullable<Text>,
86 body -> Nullable<Text>,
91 published -> Timestamp,
92 updated -> Nullable<Timestamp>,
96 banned_from_community -> Bool,
98 creator_name -> Varchar,
99 creator_avatar -> Nullable<Text>,
100 community_name -> Varchar,
101 community_removed -> Bool,
102 community_deleted -> Bool,
103 community_nsfw -> Bool,
104 number_of_comments -> BigInt,
109 user_id -> Nullable<Int4>,
110 my_vote -> Nullable<Int4>,
111 subscribed -> Nullable<Bool>,
112 read -> Nullable<Bool>,
113 saved -> Nullable<Bool>,
117 pub struct PostQueryBuilder<'a> {
118 conn: &'a PgConnection,
119 query: BoxedQuery<'a, Pg>,
120 listing_type: ListingType,
122 my_user_id: Option<i32>,
123 for_creator_id: Option<i32>,
131 impl<'a> PostQueryBuilder<'a> {
132 pub fn create(conn: &'a PgConnection) -> Self {
133 use super::post_view::post_mview::dsl::*;
135 let query = post_mview.into_boxed();
141 for_creator_id: None,
142 listing_type: ListingType::All,
143 sort: &SortType::Hot,
152 pub fn listing_type(mut self, listing_type: ListingType) -> Self {
153 self.listing_type = listing_type;
157 pub fn sort(mut self, sort: &'a SortType) -> Self {
162 pub fn for_community_id<T: MaybeOptional<i32>>(mut self, for_community_id: T) -> Self {
163 use super::post_view::post_mview::dsl::*;
164 if let Some(for_community_id) = for_community_id.get_optional() {
165 self.query = self.query.filter(community_id.eq(for_community_id));
166 self.query = self.query.then_order_by(stickied.desc());
171 pub fn for_creator_id<T: MaybeOptional<i32>>(mut self, for_creator_id: T) -> Self {
172 if let Some(for_creator_id) = for_creator_id.get_optional() {
173 self.for_creator_id = Some(for_creator_id);
178 pub fn search_term<T: MaybeOptional<String>>(mut self, search_term: T) -> Self {
179 use super::post_view::post_mview::dsl::*;
180 if let Some(search_term) = search_term.get_optional() {
181 let searcher = fuzzy_search(&search_term);
184 .filter(name.ilike(searcher.to_owned()))
185 .or_filter(body.ilike(searcher));
190 pub fn url_search<T: MaybeOptional<String>>(mut self, url_search: T) -> Self {
191 use super::post_view::post_mview::dsl::*;
192 if let Some(url_search) = url_search.get_optional() {
193 self.query = self.query.filter(url.eq(url_search));
198 pub fn my_user_id<T: MaybeOptional<i32>>(mut self, my_user_id: T) -> Self {
199 self.my_user_id = my_user_id.get_optional();
203 pub fn show_nsfw(mut self, show_nsfw: bool) -> Self {
204 self.show_nsfw = show_nsfw;
208 pub fn saved_only(mut self, saved_only: bool) -> Self {
209 self.saved_only = saved_only;
213 pub fn unread_only(mut self, unread_only: bool) -> Self {
214 self.unread_only = unread_only;
218 pub fn page<T: MaybeOptional<i64>>(mut self, page: T) -> Self {
219 self.page = page.get_optional();
223 pub fn limit<T: MaybeOptional<i64>>(mut self, limit: T) -> Self {
224 self.limit = limit.get_optional();
228 pub fn list(self) -> Result<Vec<PostView>, Error> {
229 use super::post_view::post_mview::dsl::*;
231 let mut query = self.query;
233 if let ListingType::Subscribed = self.listing_type {
234 query = query.filter(subscribed.eq(true));
237 query = match self.sort {
238 SortType::Hot => query
239 .then_order_by(hot_rank.desc())
240 .then_order_by(published.desc()),
241 SortType::New => query.then_order_by(published.desc()),
242 SortType::TopAll => query.then_order_by(score.desc()),
243 SortType::TopYear => query
244 .filter(published.gt(now - 1.years()))
245 .then_order_by(score.desc()),
246 SortType::TopMonth => query
247 .filter(published.gt(now - 1.months()))
248 .then_order_by(score.desc()),
249 SortType::TopWeek => query
250 .filter(published.gt(now - 1.weeks()))
251 .then_order_by(score.desc()),
252 SortType::TopDay => query
253 .filter(published.gt(now - 1.days()))
254 .then_order_by(score.desc()),
257 // The view lets you pass a null user_id, if you're not logged in
258 query = if let Some(my_user_id) = self.my_user_id {
259 query.filter(user_id.eq(my_user_id))
261 query.filter(user_id.is_null())
264 // If its for a specific user, show the removed / deleted
265 if let Some(for_creator_id) = self.for_creator_id {
266 query = query.filter(creator_id.eq(for_creator_id));
269 .filter(removed.eq(false))
270 .filter(deleted.eq(false))
271 .filter(community_removed.eq(false))
272 .filter(community_deleted.eq(false));
277 .filter(nsfw.eq(false))
278 .filter(community_nsfw.eq(false));
281 // TODO these are wrong, bc they'll only show saved for your logged in user, not theirs
283 query = query.filter(saved.eq(true));
286 if self.unread_only {
287 query = query.filter(read.eq(false));
290 let (limit, offset) = limit_and_offset(self.page, self.limit);
294 .filter(removed.eq(false))
295 .filter(deleted.eq(false))
296 .filter(community_removed.eq(false))
297 .filter(community_deleted.eq(false));
299 query.load::<PostView>(self.conn)
307 my_user_id: Option<i32>,
308 ) -> Result<Self, Error> {
309 use super::post_view::post_view::dsl::*;
310 use diesel::prelude::*;
312 let mut query = post_view.into_boxed();
314 query = query.filter(id.eq(from_post_id));
316 if let Some(my_user_id) = my_user_id {
317 query = query.filter(user_id.eq(my_user_id));
319 query = query.filter(user_id.is_null());
322 query.first::<Self>(conn)
328 use super::super::community::*;
329 use super::super::post::*;
330 use super::super::user::*;
334 let conn = establish_unpooled_connection();
336 let user_name = "tegan".to_string();
337 let community_name = "test_community_3".to_string();
338 let post_name = "test post 3".to_string();
340 let new_user = UserForm {
341 name: user_name.to_owned(),
342 fedi_name: "rrf".into(),
343 preferred_username: None,
344 password_encrypted: "nope".into(),
346 matrix_user_id: None,
352 theme: "darkly".into(),
353 default_sort_type: SortType::Hot as i16,
354 default_listing_type: ListingType::Subscribed as i16,
355 lang: "browser".into(),
357 send_notifications_to_email: false,
360 let inserted_user = User_::create(&conn, &new_user).unwrap();
362 let new_community = CommunityForm {
363 name: community_name.to_owned(),
364 title: "nada".to_owned(),
366 creator_id: inserted_user.id,
374 let inserted_community = Community::create(&conn, &new_community).unwrap();
376 let new_post = PostForm {
377 name: post_name.to_owned(),
380 creator_id: inserted_user.id,
381 community_id: inserted_community.id,
390 let inserted_post = Post::create(&conn, &new_post).unwrap();
392 let post_like_form = PostLikeForm {
393 post_id: inserted_post.id,
394 user_id: inserted_user.id,
398 let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap();
400 let expected_post_like = PostLike {
401 id: inserted_post_like.id,
402 post_id: inserted_post.id,
403 user_id: inserted_user.id,
404 published: inserted_post_like.published,
408 let post_like_form = PostLikeForm {
409 post_id: inserted_post.id,
410 user_id: inserted_user.id,
414 // the non user version
415 let expected_post_listing_no_user = PostView {
418 id: inserted_post.id,
419 name: post_name.to_owned(),
422 creator_id: inserted_user.id,
423 creator_name: user_name.to_owned(),
424 creator_avatar: None,
426 banned_from_community: false,
427 community_id: inserted_community.id,
432 community_name: community_name.to_owned(),
433 community_removed: false,
434 community_deleted: false,
435 community_nsfw: false,
436 number_of_comments: 0,
441 published: inserted_post.published,
449 let expected_post_listing_with_user = PostView {
450 user_id: Some(inserted_user.id),
452 id: inserted_post.id,
460 creator_id: inserted_user.id,
461 creator_name: user_name,
462 creator_avatar: None,
464 banned_from_community: false,
465 community_id: inserted_community.id,
467 community_removed: false,
468 community_deleted: false,
469 community_nsfw: false,
470 number_of_comments: 0,
475 published: inserted_post.published,
483 let read_post_listings_with_user = PostQueryBuilder::create(&conn)
484 .listing_type(ListingType::Community)
485 .sort(&SortType::New)
486 .for_community_id(inserted_community.id)
487 .my_user_id(inserted_user.id)
491 let read_post_listings_no_user = PostQueryBuilder::create(&conn)
492 .listing_type(ListingType::Community)
493 .sort(&SortType::New)
494 .for_community_id(inserted_community.id)
498 let read_post_listing_no_user = PostView::read(&conn, inserted_post.id, None).unwrap();
499 let read_post_listing_with_user =
500 PostView::read(&conn, inserted_post.id, Some(inserted_user.id)).unwrap();
502 let like_removed = PostLike::remove(&conn, &post_like_form).unwrap();
503 let num_deleted = Post::delete(&conn, inserted_post.id).unwrap();
504 Community::delete(&conn, inserted_community.id).unwrap();
505 User_::delete(&conn, inserted_user.id).unwrap();
509 expected_post_listing_with_user,
510 read_post_listings_with_user[0]
512 assert_eq!(expected_post_listing_with_user, read_post_listing_with_user);
513 assert_eq!(1, read_post_listings_with_user.len());
516 assert_eq!(expected_post_listing_no_user, read_post_listings_no_user[0]);
517 assert_eq!(expected_post_listing_no_user, read_post_listing_no_user);
518 assert_eq!(1, read_post_listings_no_user.len());
520 // assert_eq!(expected_post, inserted_post);
521 // assert_eq!(expected_post, updated_post);
522 assert_eq!(expected_post_like, inserted_post_like);
523 assert_eq!(1, like_removed);
524 assert_eq!(1, num_deleted);