]> Untitled Git - lemmy.git/blob - crates/db_schema/src/traits.rs
Default imprementations for read and delete in Crud trait (#3707)
[lemmy.git] / crates / db_schema / src / traits.rs
1 use crate::{
2   newtypes::{CommunityId, DbUrl, PersonId},
3   utils::{get_conn, DbPool},
4 };
5 use diesel::{
6   associations::HasTable,
7   dsl,
8   query_builder::{DeleteStatement, IntoUpdateTarget},
9   query_dsl::methods::{FindDsl, LimitDsl},
10   result::Error,
11   Table,
12 };
13 use diesel_async::{
14   methods::{ExecuteDsl, LoadQuery},
15   AsyncPgConnection,
16   RunQueryDsl,
17 };
18
19 /// Returned by `diesel::delete`
20 pub type Delete<T> = DeleteStatement<<T as HasTable>::Table, <T as IntoUpdateTarget>::WhereClause>;
21
22 /// Returned by `Self::table().find(id)`
23 pub type Find<T> = dsl::Find<<T as HasTable>::Table, <T as Crud>::IdType>;
24
25 pub type PrimaryKey<T> = <<T as HasTable>::Table as Table>::PrimaryKey;
26
27 // Trying to create default implementations for `create` and `update` results in a lifetime mess and weird compile errors.
28 // https://github.com/rust-lang/rust/issues/102211
29 #[async_trait]
30 pub trait Crud: HasTable + Sized
31 where
32   Self::Table: FindDsl<Self::IdType>,
33   Find<Self>: LimitDsl + IntoUpdateTarget + Send,
34   Delete<Find<Self>>: ExecuteDsl<AsyncPgConnection> + Send + 'static,
35
36   // Used by `RunQueryDsl::first`
37   dsl::Limit<Find<Self>>: LoadQuery<'static, AsyncPgConnection, Self> + Send + 'static,
38 {
39   type InsertForm;
40   type UpdateForm;
41   type IdType: Send;
42
43   async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error>;
44
45   async fn read(pool: &mut DbPool<'_>, id: Self::IdType) -> Result<Self, Error> {
46     let query: Find<Self> = Self::table().find(id);
47     let conn = &mut *get_conn(pool).await?;
48     query.first::<Self>(conn).await
49   }
50
51   /// when you want to null out a column, you have to send Some(None)), since sending None means you just don't want to update that column.
52   async fn update(
53     pool: &mut DbPool<'_>,
54     id: Self::IdType,
55     form: &Self::UpdateForm,
56   ) -> Result<Self, Error>;
57
58   async fn delete(pool: &mut DbPool<'_>, id: Self::IdType) -> Result<usize, Error> {
59     let query: Delete<Find<Self>> = diesel::delete(Self::table().find(id));
60     let conn = &mut *get_conn(pool).await?;
61     query.execute(conn).await
62   }
63 }
64
65 #[async_trait]
66 pub trait Followable {
67   type Form;
68   async fn follow(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<Self, Error>
69   where
70     Self: Sized;
71   async fn follow_accepted(
72     pool: &mut DbPool<'_>,
73     community_id: CommunityId,
74     person_id: PersonId,
75   ) -> Result<Self, Error>
76   where
77     Self: Sized;
78   async fn unfollow(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<usize, Error>
79   where
80     Self: Sized;
81 }
82
83 #[async_trait]
84 pub trait Joinable {
85   type Form;
86   async fn join(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<Self, Error>
87   where
88     Self: Sized;
89   async fn leave(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<usize, Error>
90   where
91     Self: Sized;
92 }
93
94 #[async_trait]
95 pub trait Likeable {
96   type Form;
97   type IdType;
98   async fn like(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<Self, Error>
99   where
100     Self: Sized;
101   async fn remove(
102     pool: &mut DbPool<'_>,
103     person_id: PersonId,
104     item_id: Self::IdType,
105   ) -> Result<usize, Error>
106   where
107     Self: Sized;
108 }
109
110 #[async_trait]
111 pub trait Bannable {
112   type Form;
113   async fn ban(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<Self, Error>
114   where
115     Self: Sized;
116   async fn unban(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<usize, Error>
117   where
118     Self: Sized;
119 }
120
121 #[async_trait]
122 pub trait Saveable {
123   type Form;
124   async fn save(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<Self, Error>
125   where
126     Self: Sized;
127   async fn unsave(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<usize, Error>
128   where
129     Self: Sized;
130 }
131
132 #[async_trait]
133 pub trait Blockable {
134   type Form;
135   async fn block(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<Self, Error>
136   where
137     Self: Sized;
138   async fn unblock(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<usize, Error>
139   where
140     Self: Sized;
141 }
142
143 #[async_trait]
144 pub trait Readable {
145   type Form;
146   async fn mark_as_read(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<Self, Error>
147   where
148     Self: Sized;
149   async fn mark_as_unread(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<usize, Error>
150   where
151     Self: Sized;
152 }
153
154 #[async_trait]
155 pub trait Reportable {
156   type Form;
157   type IdType;
158   async fn report(pool: &mut DbPool<'_>, form: &Self::Form) -> Result<Self, Error>
159   where
160     Self: Sized;
161   async fn resolve(
162     pool: &mut DbPool<'_>,
163     report_id: Self::IdType,
164     resolver_id: PersonId,
165   ) -> Result<usize, Error>
166   where
167     Self: Sized;
168   async fn unresolve(
169     pool: &mut DbPool<'_>,
170     report_id: Self::IdType,
171     resolver_id: PersonId,
172   ) -> Result<usize, Error>
173   where
174     Self: Sized;
175 }
176
177 pub trait JoinView {
178   type JoinTuple;
179   fn from_tuple(tuple: Self::JoinTuple) -> Self
180   where
181     Self: Sized;
182 }
183
184 #[async_trait]
185 pub trait ApubActor {
186   async fn read_from_apub_id(
187     pool: &mut DbPool<'_>,
188     object_id: &DbUrl,
189   ) -> Result<Option<Self>, Error>
190   where
191     Self: Sized;
192   /// - actor_name is the name of the community or user to read.
193   /// - include_deleted, if true, will return communities or users that were deleted/removed
194   async fn read_from_name(
195     pool: &mut DbPool<'_>,
196     actor_name: &str,
197     include_deleted: bool,
198   ) -> Result<Self, Error>
199   where
200     Self: Sized;
201   async fn read_from_name_and_domain(
202     pool: &mut DbPool<'_>,
203     actor_name: &str,
204     protocol_domain: &str,
205   ) -> Result<Self, Error>
206   where
207     Self: Sized;
208 }