]> Untitled Git - lemmy.git/blob - crates/db_schema/src/aggregates/post_aggregates.rs
Merge pull request #1850 from LemmyNet/refactor-apub
[lemmy.git] / crates / db_schema / src / aggregates / post_aggregates.rs
1 use crate::{newtypes::PostId, schema::post_aggregates};
2 use diesel::{result::Error, *};
3 use serde::{Deserialize, Serialize};
4
5 #[derive(
6   Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone,
7 )]
8 #[table_name = "post_aggregates"]
9 pub struct PostAggregates {
10   pub id: i32,
11   pub post_id: PostId,
12   pub comments: i64,
13   pub score: i64,
14   pub upvotes: i64,
15   pub downvotes: i64,
16   pub stickied: bool,
17   pub published: chrono::NaiveDateTime,
18   pub newest_comment_time_necro: chrono::NaiveDateTime, // A newest comment time, limited to 2 days, to prevent necrobumping
19   pub newest_comment_time: chrono::NaiveDateTime,
20 }
21
22 impl PostAggregates {
23   pub fn read(conn: &PgConnection, post_id: PostId) -> Result<Self, Error> {
24     post_aggregates::table
25       .filter(post_aggregates::post_id.eq(post_id))
26       .first::<Self>(conn)
27   }
28 }
29
30 #[cfg(test)]
31 mod tests {
32   use crate::{
33     aggregates::post_aggregates::PostAggregates,
34     establish_unpooled_connection,
35     source::{
36       comment::{Comment, CommentForm},
37       community::{Community, CommunityForm},
38       person::{Person, PersonForm},
39       post::{Post, PostForm, PostLike, PostLikeForm},
40     },
41     traits::{Crud, Likeable},
42   };
43   use serial_test::serial;
44
45   #[test]
46   #[serial]
47   fn test_crud() {
48     let conn = establish_unpooled_connection();
49
50     let new_person = PersonForm {
51       name: "thommy_community_agg".into(),
52       ..PersonForm::default()
53     };
54
55     let inserted_person = Person::create(&conn, &new_person).unwrap();
56
57     let another_person = PersonForm {
58       name: "jerry_community_agg".into(),
59       ..PersonForm::default()
60     };
61
62     let another_inserted_person = Person::create(&conn, &another_person).unwrap();
63
64     let new_community = CommunityForm {
65       name: "TIL_community_agg".into(),
66       title: "nada".to_owned(),
67       ..CommunityForm::default()
68     };
69
70     let inserted_community = Community::create(&conn, &new_community).unwrap();
71
72     let new_post = PostForm {
73       name: "A test post".into(),
74       creator_id: inserted_person.id,
75       community_id: inserted_community.id,
76       ..PostForm::default()
77     };
78
79     let inserted_post = Post::create(&conn, &new_post).unwrap();
80
81     let comment_form = CommentForm {
82       content: "A test comment".into(),
83       creator_id: inserted_person.id,
84       post_id: inserted_post.id,
85       ..CommentForm::default()
86     };
87
88     let inserted_comment = Comment::create(&conn, &comment_form).unwrap();
89
90     let child_comment_form = CommentForm {
91       content: "A test comment".into(),
92       creator_id: inserted_person.id,
93       post_id: inserted_post.id,
94       parent_id: Some(inserted_comment.id),
95       ..CommentForm::default()
96     };
97
98     let _inserted_child_comment = Comment::create(&conn, &child_comment_form).unwrap();
99
100     let post_like = PostLikeForm {
101       post_id: inserted_post.id,
102       person_id: inserted_person.id,
103       score: 1,
104     };
105
106     PostLike::like(&conn, &post_like).unwrap();
107
108     let post_aggs_before_delete = PostAggregates::read(&conn, inserted_post.id).unwrap();
109
110     assert_eq!(2, post_aggs_before_delete.comments);
111     assert_eq!(1, post_aggs_before_delete.score);
112     assert_eq!(1, post_aggs_before_delete.upvotes);
113     assert_eq!(0, post_aggs_before_delete.downvotes);
114
115     // Add a post dislike from the other person
116     let post_dislike = PostLikeForm {
117       post_id: inserted_post.id,
118       person_id: another_inserted_person.id,
119       score: -1,
120     };
121
122     PostLike::like(&conn, &post_dislike).unwrap();
123
124     let post_aggs_after_dislike = PostAggregates::read(&conn, inserted_post.id).unwrap();
125
126     assert_eq!(2, post_aggs_after_dislike.comments);
127     assert_eq!(0, post_aggs_after_dislike.score);
128     assert_eq!(1, post_aggs_after_dislike.upvotes);
129     assert_eq!(1, post_aggs_after_dislike.downvotes);
130
131     // Remove the parent comment
132     Comment::delete(&conn, inserted_comment.id).unwrap();
133     let after_comment_delete = PostAggregates::read(&conn, inserted_post.id).unwrap();
134     assert_eq!(0, after_comment_delete.comments);
135     assert_eq!(0, after_comment_delete.score);
136     assert_eq!(1, after_comment_delete.upvotes);
137     assert_eq!(1, after_comment_delete.downvotes);
138
139     // Remove the first post like
140     PostLike::remove(&conn, inserted_person.id, inserted_post.id).unwrap();
141     let after_like_remove = PostAggregates::read(&conn, inserted_post.id).unwrap();
142     assert_eq!(0, after_like_remove.comments);
143     assert_eq!(-1, after_like_remove.score);
144     assert_eq!(0, after_like_remove.upvotes);
145     assert_eq!(1, after_like_remove.downvotes);
146
147     // This should delete all the associated rows, and fire triggers
148     Person::delete(&conn, another_inserted_person.id).unwrap();
149     let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
150     assert_eq!(1, person_num_deleted);
151
152     // Delete the community
153     let community_num_deleted = Community::delete(&conn, inserted_community.id).unwrap();
154     assert_eq!(1, community_num_deleted);
155
156     // Should be none found, since the creator was deleted
157     let after_delete = PostAggregates::read(&conn, inserted_post.id);
158     assert!(after_delete.is_err());
159   }
160 }