]> Untitled Git - lemmy.git/commitdiff
Default imprementations for read and delete in Crud trait (#3707)
authordullbananas <dull.bananas0@gmail.com>
Tue, 1 Aug 2023 14:34:10 +0000 (07:34 -0700)
committerGitHub <noreply@github.com>
Tue, 1 Aug 2023 14:34:10 +0000 (10:34 -0400)
* h

* Start doing stuff

* Default impl for Crud::read

* Simplify Crud::read lifetimes

* fmt

* Stuff

* Stuff

* Successfully make default read implementation work

* Restore Person::read

* Clean up default Crud::read and rename 'query2

* Replace filter with find

* Attempt default Crud::create

* Change Crud to Crud<'a> (won't compile)

* Revert "Change Crud to Crud<'a> (won't compile)"

This reverts commit 7ed20f5f713600bd48c85aad0848d8dbaae56503.

* Default Crud::delete

* Remove Crud::delete definitions that match default

* Remove commented Site::read

* Insert trait

* Revert "Insert trait"

This reverts commit 9d780c24035d3a9fb12968d3009a28724046dc3a.

* Use non-borrowed forms

* Revert "Use non-borrowed forms"

This reverts commit d2dd4425634b54ef105aab44f1c37cc10a32491e.

* Revert "Revert "Change Crud to Crud<'a> (won't compile)""

This reverts commit 25a27165a8ef56495e9f605ac15c9924b101d1bf.

* Fix lifetime for everything except Crud::delete

* Fix Crud::delete

* Add comment about futures

* Attempt Crud::create

* Attempt separate CrudBounds

* Revert "Attempt separate CrudBounds"

This reverts commit 1b4ca321c3d2a1d045e2f4c542c593582e9c6d80.

* Try to fix Crud::create

* Move lifetime parameters to associated types

* Revert "Move lifetime parameters to associated types"

This reverts commit af1bc858ce5e1dacddc4bbded2da7e4b7237e237.

* Revert "Try to fix Crud::create"

This reverts commit eec238496c38127cbf3d542b7cfd57ec55622d1f.

* Revert "Revert "Attempt separate CrudBounds""

This reverts commit 1ec33ce5022c58a5ad079ed7f5c220fafe5f0a5f.

* Revert "Attempt separate CrudBounds"

This reverts commit 1b4ca321c3d2a1d045e2f4c542c593582e9c6d80.

* Revert "Attempt Crud::create"

This reverts commit 47e8071b6826f27e2a562680b4948c37dffa68cb.

* Revert "Add comment about futures"

This reverts commit b266b1465393995b3be51d5ba207d5249560884f.

* Revert "Fix Crud::delete"

This reverts commit 3abcce2eec55208993dd9c7c3e51cff83412d15a.

* Revert "Fix lifetime for everything except Crud::delete"

This reverts commit c1ad7a161bbc8495dbfb8b52073f35ae88519da6.

* Revert "Revert "Revert "Change Crud to Crud<'a> (won't compile)"""

This reverts commit 3129cd0fc302f34bc0aad59987b9d0eb1139076c.

* Clean up

* Update site.rs

13 files changed:
crates/db_schema/src/impls/comment.rs
crates/db_schema/src/impls/comment_reply.rs
crates/db_schema/src/impls/community.rs
crates/db_schema/src/impls/local_user.rs
crates/db_schema/src/impls/moderator.rs
crates/db_schema/src/impls/password_reset_request.rs
crates/db_schema/src/impls/person.rs
crates/db_schema/src/impls/person_mention.rs
crates/db_schema/src/impls/post.rs
crates/db_schema/src/impls/private_message.rs
crates/db_schema/src/impls/registration_application.rs
crates/db_schema/src/impls/site.rs
crates/db_schema/src/traits.rs

index 5346343264036523d86359132183463de95a0b01..88757cd023f5a4b15ee01a925d6afc4395733948 100644 (file)
@@ -156,15 +156,6 @@ impl Crud for Comment {
   type InsertForm = CommentInsertForm;
   type UpdateForm = CommentUpdateForm;
   type IdType = CommentId;
-  async fn read(pool: &mut DbPool<'_>, comment_id: CommentId) -> Result<Self, Error> {
-    let conn = &mut get_conn(pool).await?;
-    comment.find(comment_id).first::<Self>(conn).await
-  }
-
-  async fn delete(pool: &mut DbPool<'_>, comment_id: CommentId) -> Result<usize, Error> {
-    let conn = &mut get_conn(pool).await?;
-    diesel::delete(comment.find(comment_id)).execute(conn).await
-  }
 
   /// This is unimplemented, use [[Comment::create]]
   async fn create(_pool: &mut DbPool<'_>, _comment_form: &Self::InsertForm) -> Result<Self, Error> {
index eeb171f58e657276297e183005ca4524a4f36176..c5b5a3c6a59d7608d779ce0e7cd916d72838a0bb 100644 (file)
@@ -13,13 +13,6 @@ impl Crud for CommentReply {
   type InsertForm = CommentReplyInsertForm;
   type UpdateForm = CommentReplyUpdateForm;
   type IdType = CommentReplyId;
-  async fn read(pool: &mut DbPool<'_>, comment_reply_id: CommentReplyId) -> Result<Self, Error> {
-    let conn = &mut get_conn(pool).await?;
-    comment_reply
-      .find(comment_reply_id)
-      .first::<Self>(conn)
-      .await
-  }
 
   async fn create(
     pool: &mut DbPool<'_>,
index 258e4150442b9473de31a10583381408209f6662..2d0fcfe5725d147e4f834215cee8f93ee722e3d3 100644 (file)
@@ -27,20 +27,6 @@ impl Crud for Community {
   type InsertForm = CommunityInsertForm;
   type UpdateForm = CommunityUpdateForm;
   type IdType = CommunityId;
-  async fn read(pool: &mut DbPool<'_>, community_id: CommunityId) -> Result<Self, Error> {
-    let conn = &mut get_conn(pool).await?;
-    community::table
-      .find(community_id)
-      .first::<Self>(conn)
-      .await
-  }
-
-  async fn delete(pool: &mut DbPool<'_>, community_id: CommunityId) -> Result<usize, Error> {
-    let conn = &mut get_conn(pool).await?;
-    diesel::delete(community::table.find(community_id))
-      .execute(conn)
-      .await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
     let is_new_community = match &form.actor_id {
index 0a72811ae37e4b7d203818ed6e9b31f83b16fb6c..6ef3421d32d17ef5d2debc932e30505422accece 100644 (file)
@@ -69,16 +69,7 @@ impl Crud for LocalUser {
   type InsertForm = LocalUserInsertForm;
   type UpdateForm = LocalUserUpdateForm;
   type IdType = LocalUserId;
-  async fn read(pool: &mut DbPool<'_>, local_user_id: LocalUserId) -> Result<Self, Error> {
-    let conn = &mut get_conn(pool).await?;
-    local_user.find(local_user_id).first::<Self>(conn).await
-  }
-  async fn delete(pool: &mut DbPool<'_>, local_user_id: LocalUserId) -> Result<usize, Error> {
-    let conn = &mut get_conn(pool).await?;
-    diesel::delete(local_user.find(local_user_id))
-      .execute(conn)
-      .await
-  }
+
   async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
     let conn = &mut get_conn(pool).await?;
     let mut form_with_encrypted_password = form.clone();
index 12344f71cff1e41d59a81a78db3c4c0e222fccee..a4c300b2a07138d8a77a0472449c83d5cee4c845 100644 (file)
@@ -42,11 +42,6 @@ impl Crud for ModRemovePost {
   type InsertForm = ModRemovePostForm;
   type UpdateForm = ModRemovePostForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::mod_remove_post::dsl::mod_remove_post;
-    let conn = &mut get_conn(pool).await?;
-    mod_remove_post.find(from_id).first::<Self>(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &ModRemovePostForm) -> Result<Self, Error> {
     use crate::schema::mod_remove_post::dsl::mod_remove_post;
@@ -76,11 +71,6 @@ impl Crud for ModLockPost {
   type InsertForm = ModLockPostForm;
   type UpdateForm = ModLockPostForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::mod_lock_post::dsl::mod_lock_post;
-    let conn = &mut get_conn(pool).await?;
-    mod_lock_post.find(from_id).first::<Self>(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &ModLockPostForm) -> Result<Self, Error> {
     use crate::schema::mod_lock_post::dsl::mod_lock_post;
@@ -110,11 +100,6 @@ impl Crud for ModFeaturePost {
   type InsertForm = ModFeaturePostForm;
   type UpdateForm = ModFeaturePostForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::mod_feature_post::dsl::mod_feature_post;
-    let conn = &mut get_conn(pool).await?;
-    mod_feature_post.find(from_id).first::<Self>(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &ModFeaturePostForm) -> Result<Self, Error> {
     use crate::schema::mod_feature_post::dsl::mod_feature_post;
@@ -144,11 +129,6 @@ impl Crud for ModRemoveComment {
   type InsertForm = ModRemoveCommentForm;
   type UpdateForm = ModRemoveCommentForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::mod_remove_comment::dsl::mod_remove_comment;
-    let conn = &mut get_conn(pool).await?;
-    mod_remove_comment.find(from_id).first::<Self>(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &ModRemoveCommentForm) -> Result<Self, Error> {
     use crate::schema::mod_remove_comment::dsl::mod_remove_comment;
@@ -178,11 +158,6 @@ impl Crud for ModRemoveCommunity {
   type InsertForm = ModRemoveCommunityForm;
   type UpdateForm = ModRemoveCommunityForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::mod_remove_community::dsl::mod_remove_community;
-    let conn = &mut get_conn(pool).await?;
-    mod_remove_community.find(from_id).first::<Self>(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &ModRemoveCommunityForm) -> Result<Self, Error> {
     use crate::schema::mod_remove_community::dsl::mod_remove_community;
@@ -212,14 +187,6 @@ impl Crud for ModBanFromCommunity {
   type InsertForm = ModBanFromCommunityForm;
   type UpdateForm = ModBanFromCommunityForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::mod_ban_from_community::dsl::mod_ban_from_community;
-    let conn = &mut get_conn(pool).await?;
-    mod_ban_from_community
-      .find(from_id)
-      .first::<Self>(conn)
-      .await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &ModBanFromCommunityForm) -> Result<Self, Error> {
     use crate::schema::mod_ban_from_community::dsl::mod_ban_from_community;
@@ -249,11 +216,6 @@ impl Crud for ModBan {
   type InsertForm = ModBanForm;
   type UpdateForm = ModBanForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::mod_ban::dsl::mod_ban;
-    let conn = &mut get_conn(pool).await?;
-    mod_ban.find(from_id).first::<Self>(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &ModBanForm) -> Result<Self, Error> {
     use crate::schema::mod_ban::dsl::mod_ban;
@@ -280,12 +242,6 @@ impl Crud for ModHideCommunity {
   type UpdateForm = ModHideCommunityForm;
   type IdType = i32;
 
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::mod_hide_community::dsl::mod_hide_community;
-    let conn = &mut get_conn(pool).await?;
-    mod_hide_community.find(from_id).first::<Self>(conn).await
-  }
-
   async fn create(pool: &mut DbPool<'_>, form: &ModHideCommunityForm) -> Result<Self, Error> {
     use crate::schema::mod_hide_community::dsl::mod_hide_community;
     let conn = &mut get_conn(pool).await?;
@@ -314,11 +270,6 @@ impl Crud for ModAddCommunity {
   type InsertForm = ModAddCommunityForm;
   type UpdateForm = ModAddCommunityForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::mod_add_community::dsl::mod_add_community;
-    let conn = &mut get_conn(pool).await?;
-    mod_add_community.find(from_id).first::<Self>(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &ModAddCommunityForm) -> Result<Self, Error> {
     use crate::schema::mod_add_community::dsl::mod_add_community;
@@ -348,14 +299,6 @@ impl Crud for ModTransferCommunity {
   type InsertForm = ModTransferCommunityForm;
   type UpdateForm = ModTransferCommunityForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::mod_transfer_community::dsl::mod_transfer_community;
-    let conn = &mut get_conn(pool).await?;
-    mod_transfer_community
-      .find(from_id)
-      .first::<Self>(conn)
-      .await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &ModTransferCommunityForm) -> Result<Self, Error> {
     use crate::schema::mod_transfer_community::dsl::mod_transfer_community;
@@ -385,11 +328,6 @@ impl Crud for ModAdd {
   type InsertForm = ModAddForm;
   type UpdateForm = ModAddForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::mod_add::dsl::mod_add;
-    let conn = &mut get_conn(pool).await?;
-    mod_add.find(from_id).first::<Self>(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &ModAddForm) -> Result<Self, Error> {
     use crate::schema::mod_add::dsl::mod_add;
@@ -415,11 +353,6 @@ impl Crud for AdminPurgePerson {
   type InsertForm = AdminPurgePersonForm;
   type UpdateForm = AdminPurgePersonForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::admin_purge_person::dsl::admin_purge_person;
-    let conn = &mut get_conn(pool).await?;
-    admin_purge_person.find(from_id).first::<Self>(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
     use crate::schema::admin_purge_person::dsl::admin_purge_person;
@@ -449,14 +382,6 @@ impl Crud for AdminPurgeCommunity {
   type InsertForm = AdminPurgeCommunityForm;
   type UpdateForm = AdminPurgeCommunityForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::admin_purge_community::dsl::admin_purge_community;
-    let conn = &mut get_conn(pool).await?;
-    admin_purge_community
-      .find(from_id)
-      .first::<Self>(conn)
-      .await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
     use crate::schema::admin_purge_community::dsl::admin_purge_community;
@@ -486,11 +411,6 @@ impl Crud for AdminPurgePost {
   type InsertForm = AdminPurgePostForm;
   type UpdateForm = AdminPurgePostForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::admin_purge_post::dsl::admin_purge_post;
-    let conn = &mut get_conn(pool).await?;
-    admin_purge_post.find(from_id).first::<Self>(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
     use crate::schema::admin_purge_post::dsl::admin_purge_post;
@@ -520,11 +440,6 @@ impl Crud for AdminPurgeComment {
   type InsertForm = AdminPurgeCommentForm;
   type UpdateForm = AdminPurgeCommentForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result<Self, Error> {
-    use crate::schema::admin_purge_comment::dsl::admin_purge_comment;
-    let conn = &mut get_conn(pool).await?;
-    admin_purge_comment.find(from_id).first::<Self>(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
     use crate::schema::admin_purge_comment::dsl::admin_purge_comment;
index ae4483d6ef53ef3bfdfae50a9f84ea7c6d0f92ef..9daaa1664d2d2d892fd2e890aefaaba1fe0fd8ac 100644 (file)
@@ -24,13 +24,7 @@ impl Crud for PasswordResetRequest {
   type InsertForm = PasswordResetRequestForm;
   type UpdateForm = PasswordResetRequestForm;
   type IdType = i32;
-  async fn read(pool: &mut DbPool<'_>, password_reset_request_id: i32) -> Result<Self, Error> {
-    let conn = &mut get_conn(pool).await?;
-    password_reset_request
-      .find(password_reset_request_id)
-      .first::<Self>(conn)
-      .await
-  }
+
   async fn create(pool: &mut DbPool<'_>, form: &PasswordResetRequestForm) -> Result<Self, Error> {
     let conn = &mut get_conn(pool).await?;
     insert_into(password_reset_request)
index 2e086dcb6d3f1cb9a8eda5ec61ec38ca9b142103..53f4a4df01118e2aa2b857397fee0b2ffa87a9d2 100644 (file)
@@ -27,12 +27,7 @@ impl Crud for Person {
       .first::<Self>(conn)
       .await
   }
-  async fn delete(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<usize, Error> {
-    let conn = &mut get_conn(pool).await?;
-    diesel::delete(person::table.find(person_id))
-      .execute(conn)
-      .await
-  }
+
   async fn create(pool: &mut DbPool<'_>, form: &PersonInsertForm) -> Result<Self, Error> {
     let conn = &mut get_conn(pool).await?;
     insert_into(person::table)
index 27c04217e0f1e0e42871fe9535471d695986f935..f2441f00cef92fc343356db550930c46914846f5 100644 (file)
@@ -13,13 +13,6 @@ impl Crud for PersonMention {
   type InsertForm = PersonMentionInsertForm;
   type UpdateForm = PersonMentionUpdateForm;
   type IdType = PersonMentionId;
-  async fn read(pool: &mut DbPool<'_>, person_mention_id: PersonMentionId) -> Result<Self, Error> {
-    let conn = &mut get_conn(pool).await?;
-    person_mention
-      .find(person_mention_id)
-      .first::<Self>(conn)
-      .await
-  }
 
   async fn create(
     pool: &mut DbPool<'_>,
index f10d0cd2793ff515dc2ff24190d02cd87e8bbdba..60b8af2cea075547baefa60f2a8114166fa02530 100644 (file)
@@ -38,15 +38,6 @@ impl Crud for Post {
   type InsertForm = PostInsertForm;
   type UpdateForm = PostUpdateForm;
   type IdType = PostId;
-  async fn read(pool: &mut DbPool<'_>, post_id: PostId) -> Result<Self, Error> {
-    let conn = &mut get_conn(pool).await?;
-    post.find(post_id).first::<Self>(conn).await
-  }
-
-  async fn delete(pool: &mut DbPool<'_>, post_id: PostId) -> Result<usize, Error> {
-    let conn = &mut get_conn(pool).await?;
-    diesel::delete(post.find(post_id)).execute(conn).await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
     let conn = &mut get_conn(pool).await?;
index fb1d4b905656662ba925c8431acc2b3e596728f8..d422f0d2370fc1a2eb39366558cb460c42d6f7c8 100644 (file)
@@ -15,16 +15,6 @@ impl Crud for PrivateMessage {
   type InsertForm = PrivateMessageInsertForm;
   type UpdateForm = PrivateMessageUpdateForm;
   type IdType = PrivateMessageId;
-  async fn read(
-    pool: &mut DbPool<'_>,
-    private_message_id: PrivateMessageId,
-  ) -> Result<Self, Error> {
-    let conn = &mut get_conn(pool).await?;
-    private_message
-      .find(private_message_id)
-      .first::<Self>(conn)
-      .await
-  }
 
   async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
     let conn = &mut get_conn(pool).await?;
@@ -48,12 +38,6 @@ impl Crud for PrivateMessage {
       .get_result::<Self>(conn)
       .await
   }
-  async fn delete(pool: &mut DbPool<'_>, pm_id: Self::IdType) -> Result<usize, Error> {
-    let conn = &mut get_conn(pool).await?;
-    diesel::delete(private_message.find(pm_id))
-      .execute(conn)
-      .await
-  }
 }
 
 impl PrivateMessage {
index c8c6228898d8e37ba9768d6b3c5c2ea497363b49..c4df7ba69ea231edfaad935558508e617356507f 100644 (file)
@@ -26,11 +26,6 @@ impl Crud for RegistrationApplication {
       .await
   }
 
-  async fn read(pool: &mut DbPool<'_>, id_: Self::IdType) -> Result<Self, Error> {
-    let conn = &mut get_conn(pool).await?;
-    registration_application.find(id_).first::<Self>(conn).await
-  }
-
   async fn update(
     pool: &mut DbPool<'_>,
     id_: Self::IdType,
@@ -42,13 +37,6 @@ impl Crud for RegistrationApplication {
       .get_result::<Self>(conn)
       .await
   }
-
-  async fn delete(pool: &mut DbPool<'_>, id_: Self::IdType) -> Result<usize, Error> {
-    let conn = &mut get_conn(pool).await?;
-    diesel::delete(registration_application.find(id_))
-      .execute(conn)
-      .await
-  }
 }
 
 impl RegistrationApplication {
index 2820e9cd5ccf07324603adf0a0373b294db2608a..85e2b1f25e2b556ae8f4e7fcba3f3c4f7f682bbb 100644 (file)
@@ -58,11 +58,6 @@ impl Crud for Site {
       .get_result::<Self>(conn)
       .await
   }
-
-  async fn delete(pool: &mut DbPool<'_>, site_id: SiteId) -> Result<usize, Error> {
-    let conn = &mut get_conn(pool).await?;
-    diesel::delete(site.find(site_id)).execute(conn).await
-  }
 }
 
 impl Site {
index 0ba0cbff642d54d7f7f3b9e782a66938dba36c47..07f0b07e25937c1481a6a2c879f6a3a70cdee036 100644 (file)
@@ -1,34 +1,64 @@
 use crate::{
   newtypes::{CommunityId, DbUrl, PersonId},
-  utils::DbPool,
+  utils::{get_conn, DbPool},
 };
-use diesel::result::Error;
+use diesel::{
+  associations::HasTable,
+  dsl,
+  query_builder::{DeleteStatement, IntoUpdateTarget},
+  query_dsl::methods::{FindDsl, LimitDsl},
+  result::Error,
+  Table,
+};
+use diesel_async::{
+  methods::{ExecuteDsl, LoadQuery},
+  AsyncPgConnection,
+  RunQueryDsl,
+};
+
+/// Returned by `diesel::delete`
+pub type Delete<T> = DeleteStatement<<T as HasTable>::Table, <T as IntoUpdateTarget>::WhereClause>;
+
+/// Returned by `Self::table().find(id)`
+pub type Find<T> = dsl::Find<<T as HasTable>::Table, <T as Crud>::IdType>;
+
+pub type PrimaryKey<T> = <<T as HasTable>::Table as Table>::PrimaryKey;
 
+// Trying to create default implementations for `create` and `update` results in a lifetime mess and weird compile errors.
+// https://github.com/rust-lang/rust/issues/102211
 #[async_trait]
-pub trait Crud {
+pub trait Crud: HasTable + Sized
+where
+  Self::Table: FindDsl<Self::IdType>,
+  Find<Self>: LimitDsl + IntoUpdateTarget + Send,
+  Delete<Find<Self>>: ExecuteDsl<AsyncPgConnection> + Send + 'static,
+
+  // Used by `RunQueryDsl::first`
+  dsl::Limit<Find<Self>>: LoadQuery<'static, AsyncPgConnection, Self> + Send + 'static,
+{
   type InsertForm;
   type UpdateForm;
-  type IdType;
-  async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error>
-  where
-    Self: Sized;
-  async fn read(pool: &mut DbPool<'_>, id: Self::IdType) -> Result<Self, Error>
-  where
-    Self: Sized;
+  type IdType: Send;
+
+  async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error>;
+
+  async fn read(pool: &mut DbPool<'_>, id: Self::IdType) -> Result<Self, Error> {
+    let query: Find<Self> = Self::table().find(id);
+    let conn = &mut *get_conn(pool).await?;
+    query.first::<Self>(conn).await
+  }
+
   /// 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.
   async fn update(
     pool: &mut DbPool<'_>,
     id: Self::IdType,
     form: &Self::UpdateForm,
-  ) -> Result<Self, Error>
-  where
-    Self: Sized;
-  async fn delete(_pool: &mut DbPool<'_>, _id: Self::IdType) -> Result<usize, Error>
-  where
-    Self: Sized,
-    Self::IdType: Send,
-  {
-    async { Err(Error::NotFound) }.await
+  ) -> Result<Self, Error>;
+
+  async fn delete(pool: &mut DbPool<'_>, id: Self::IdType) -> Result<usize, Error> {
+    let query: Delete<Find<Self>> = diesel::delete(Self::table().find(id));
+    let conn = &mut *get_conn(pool).await?;
+    query.execute(conn).await
   }
 }