+/// 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: 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,
+{