Remove id column and use different primary key on some tables (#4093)

* post_saved

* fmt

* remove unique and not null

* put person_id first in primary key and remove index

* use post_saved.find

* change captcha_answer

* remove removal of not null

* comment_aggregates

* comment_like

* comment_saved

* aggregates

* remove "\"

* deduplicate site_aggregates

* person_post_aggregates

* community_moderator

* community_block

* community_person_ban

* custom_emoji_keyword

* federation allow/block list

* federation_queue_state

* instance_block

* local_site_rate_limit, local_user_language, login_token

* person_ban, person_block, person_follower, post_like, post_read, received_activity

* community_follower, community_language, site_language

* fmt

* image_upload

* remove unused newtypes

* remove more indexes

* use .find

* merge

* fix site_aggregates_site function

* fmt

* Primary keys dess (#17)

* Also order reports by oldest first (ref #4123) (#4129)

* Support signed fetch for federation (fixes #868) (#4125)

* Support signed fetch for federation (fixes #868)

* taplo

* add federation queue state to get_federated_instances api (#4104)

* add federation queue state to get_federated_instances api

* feature gate

* move retry sleep function

* move stuff around

* Add UI setting for collapsing bot comments. Fixes #3838 (#4098)

* Add UI setting for collapsing bot comments. Fixes #3838

* Fixing clippy check.

* Only keep sent and received activities for 7 days (fixes #4113, fixes #4110) (#4131)

* Only check auth secure on release mode. (#4127)

* Only check auth secure on release mode.

* Fixing wrong js-client.

* Adding is_debug_mode var.

* Fixing the desktop image on the README. (#4135)

* Delete dupes and add possibly missing unique constraint on person_aggregates.

* Fixing clippy lints.

---------

Co-authored-by: Nutomic <me@nutomic.com>
Co-authored-by: phiresky <phireskyde+git@gmail.com>

* fmt

* Update community_block.rs

* Update instance_block.rs

* Update person_block.rs

* Update person_block.rs

---------

Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
Co-authored-by: Nutomic <me@nutomic.com>
Co-authored-by: phiresky <phireskyde+git@gmail.com>
This commit is contained in:
dullbananas 2023-11-13 06:14:07 -07:00 committed by GitHub
parent 1dc6c60760
commit 8e2cbc9a0f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 597 additions and 333 deletions

View file

@ -11,7 +11,7 @@ impl CommentAggregates {
pub async fn read(pool: &mut DbPool<'_>, comment_id: CommentId) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
comment_aggregates::table
.filter(comment_aggregates::comment_id.eq(comment_id))
.find(comment_id)
.first::<Self>(conn)
.await
}
@ -22,8 +22,7 @@ impl CommentAggregates {
) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
diesel::update(comment_aggregates::table)
.filter(comment_aggregates::comment_id.eq(comment_id))
diesel::update(comment_aggregates::table.find(comment_id))
.set(comment_aggregates::hot_rank.eq(hot_rank(
comment_aggregates::score,
comment_aggregates::published,

View file

@ -1,10 +1,7 @@
use crate::{
aggregates::structs::CommunityAggregates,
newtypes::CommunityId,
schema::{
community_aggregates,
community_aggregates::{community_id, subscribers},
},
schema::{community_aggregates, community_aggregates::subscribers},
utils::{get_conn, DbPool},
};
use diesel::{result::Error, ExpressionMethods, QueryDsl};
@ -14,7 +11,7 @@ impl CommunityAggregates {
pub async fn read(pool: &mut DbPool<'_>, for_community_id: CommunityId) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
community_aggregates::table
.filter(community_id.eq(for_community_id))
.find(for_community_id)
.first::<Self>(conn)
.await
}
@ -26,7 +23,7 @@ impl CommunityAggregates {
) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
let new_subscribers: i64 = new_subscribers.into();
diesel::update(community_aggregates::table.filter(community_id.eq(for_community_id)))
diesel::update(community_aggregates::table.find(for_community_id))
.set(subscribers.eq(new_subscribers))
.get_result::<Self>(conn)
.await

View file

@ -4,14 +4,14 @@ use crate::{
schema::person_aggregates,
utils::{get_conn, DbPool},
};
use diesel::{result::Error, ExpressionMethods, QueryDsl};
use diesel::{result::Error, QueryDsl};
use diesel_async::RunQueryDsl;
impl PersonAggregates {
pub async fn read(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
person_aggregates::table
.filter(person_aggregates::person_id.eq(person_id))
.find(person_id)
.first::<Self>(conn)
.await
}

View file

@ -1,11 +1,10 @@
use crate::{
aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm},
diesel::BoolExpressionMethods,
newtypes::{PersonId, PostId},
schema::person_post_aggregates::dsl::{person_id, person_post_aggregates, post_id},
utils::{get_conn, DbPool},
};
use diesel::{insert_into, result::Error, ExpressionMethods, QueryDsl};
use diesel::{insert_into, result::Error, QueryDsl};
use diesel_async::RunQueryDsl;
impl PersonPostAggregates {
@ -29,7 +28,7 @@ impl PersonPostAggregates {
) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
person_post_aggregates
.filter(post_id.eq(post_id_).and(person_id.eq(person_id_)))
.find((person_id_, post_id_))
.first::<Self>(conn)
.await
}

View file

@ -15,7 +15,7 @@ impl PostAggregates {
pub async fn read(pool: &mut DbPool<'_>, post_id: PostId) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
post_aggregates::table
.filter(post_aggregates::post_id.eq(post_id))
.find(post_id)
.first::<Self>(conn)
.await
}
@ -33,8 +33,7 @@ impl PostAggregates {
.first::<i64>(conn)
.await?;
diesel::update(post_aggregates::table)
.filter(post_aggregates::post_id.eq(post_id))
diesel::update(post_aggregates::table.find(post_id))
.set((
post_aggregates::hot_rank.eq(hot_rank(post_aggregates::score, post_aggregates::published)),
post_aggregates::hot_rank_active.eq(hot_rank(

View file

@ -16,10 +16,10 @@ use ts_rs::TS;
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
#[cfg_attr(feature = "full", diesel(table_name = comment_aggregates))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
#[cfg_attr(feature = "full", diesel(primary_key(comment_id)))]
#[cfg_attr(feature = "full", ts(export))]
/// Aggregate data for a comment.
pub struct CommentAggregates {
pub id: i32,
pub comment_id: CommentId,
pub score: i64,
pub upvotes: i64,
@ -40,10 +40,10 @@ pub struct CommentAggregates {
feature = "full",
diesel(belongs_to(crate::source::community::Community))
)]
#[cfg_attr(feature = "full", diesel(primary_key(community_id)))]
#[cfg_attr(feature = "full", ts(export))]
/// Aggregate data for a community.
pub struct CommunityAggregates {
pub id: i32,
pub community_id: CommunityId,
pub subscribers: i64,
pub posts: i64,
@ -65,10 +65,10 @@ pub struct CommunityAggregates {
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
#[cfg_attr(feature = "full", diesel(table_name = person_aggregates))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::person::Person)))]
#[cfg_attr(feature = "full", diesel(primary_key(person_id)))]
#[cfg_attr(feature = "full", ts(export))]
/// Aggregate data for a person.
pub struct PersonAggregates {
pub id: i32,
pub person_id: PersonId,
pub post_count: i64,
#[serde(skip)]
@ -82,10 +82,10 @@ pub struct PersonAggregates {
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
#[cfg_attr(feature = "full", diesel(table_name = post_aggregates))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::post::Post)))]
#[cfg_attr(feature = "full", diesel(primary_key(post_id)))]
#[cfg_attr(feature = "full", ts(export))]
/// Aggregate data for a post.
pub struct PostAggregates {
pub id: i32,
pub post_id: PostId,
pub comments: i64,
pub score: i64,
@ -124,10 +124,10 @@ pub struct PostAggregates {
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
#[cfg_attr(feature = "full", diesel(table_name = person_post_aggregates))]
#[cfg_attr(feature = "full", diesel(primary_key(person_id, post_id)))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::person::Person)))]
/// Aggregate data for a person's post.
pub struct PersonPostAggregates {
pub id: i32,
pub person_id: PersonId,
pub post_id: PostId,
/// The number of comments they've read on that post.
@ -151,10 +151,10 @@ pub struct PersonPostAggregatesForm {
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
#[cfg_attr(feature = "full", diesel(table_name = site_aggregates))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::site::Site)))]
#[cfg_attr(feature = "full", diesel(primary_key(site_id)))]
#[cfg_attr(feature = "full", ts(export))]
/// Aggregate data for a site.
pub struct SiteAggregates {
pub id: i32,
pub site_id: SiteId,
pub users: i64,
pub posts: i64,

View file

@ -39,16 +39,15 @@ impl SentActivity {
impl ReceivedActivity {
pub async fn create(pool: &mut DbPool<'_>, ap_id_: &DbUrl) -> Result<(), Error> {
use crate::schema::received_activity::dsl::{ap_id, id, received_activity};
use crate::schema::received_activity::dsl::{ap_id, received_activity};
let conn = &mut get_conn(pool).await?;
let res = insert_into(received_activity)
let rows_affected = insert_into(received_activity)
.values(ap_id.eq(ap_id_))
.on_conflict_do_nothing()
.returning(id)
.get_result::<i64>(conn)
.execute(conn)
.await
.optional()?;
if res.is_some() {
if rows_affected == Some(1) {
// new activity inserted successfully
Ok(())
} else {

View file

@ -119,7 +119,7 @@ impl SiteLanguage {
site::table
.inner_join(local_site::table)
.inner_join(site_language::table)
.order(site_language::id)
.order(site_language::language_id)
.select(site_language::language_id)
.load(conn)
.await
@ -191,14 +191,12 @@ impl CommunityLanguage {
for_language_id: Option<LanguageId>,
for_community_id: CommunityId,
) -> Result<(), LemmyError> {
use crate::schema::community_language::dsl::{community_id, community_language, language_id};
use crate::schema::community_language::dsl::community_language;
let conn = &mut get_conn(pool).await?;
if let Some(for_language_id) = for_language_id {
let is_allowed = select(exists(
community_language
.filter(language_id.eq(for_language_id))
.filter(community_id.eq(for_community_id)),
community_language.find((for_community_id, for_language_id)),
))
.get_result(conn)
.await?;

View file

@ -1,5 +1,5 @@
use crate::{
schema::captcha_answer::dsl::{answer, captcha_answer, uuid},
schema::captcha_answer::dsl::{answer, captcha_answer},
source::captcha_answer::{CaptchaAnswer, CaptchaAnswerForm, CheckCaptchaAnswer},
utils::{functions::lower, get_conn, DbPool},
};
@ -31,16 +31,15 @@ impl CaptchaAnswer {
let conn = &mut get_conn(pool).await?;
// fetch requested captcha
let captcha_exists = select(exists(
captcha_answer
.filter((uuid).eq(to_check.uuid))
.filter(lower(answer).eq(to_check.answer.to_lowercase().clone())),
))
.get_result::<bool>(conn)
.await?;
let captcha_exists =
select(exists(captcha_answer.find(to_check.uuid).filter(
lower(answer).eq(to_check.answer.to_lowercase().clone()),
)))
.get_result::<bool>(conn)
.await?;
// delete checked captcha
delete(captcha_answer.filter(uuid.eq(to_check.uuid)))
delete(captcha_answer.find(to_check.uuid))
.execute(conn)
.await?;

View file

@ -192,18 +192,14 @@ impl Likeable for CommentLike {
}
async fn remove(
pool: &mut DbPool<'_>,
person_id_: PersonId,
comment_id_: CommentId,
person_id: PersonId,
comment_id: CommentId,
) -> Result<usize, Error> {
use crate::schema::comment_like::dsl::{comment_id, comment_like, person_id};
use crate::schema::comment_like::dsl::comment_like;
let conn = &mut get_conn(pool).await?;
diesel::delete(
comment_like
.filter(comment_id.eq(comment_id_))
.filter(person_id.eq(person_id_)),
)
.execute(conn)
.await
diesel::delete(comment_like.find((person_id, comment_id)))
.execute(conn)
.await
}
}
@ -228,12 +224,10 @@ impl Saveable for CommentSaved {
pool: &mut DbPool<'_>,
comment_saved_form: &CommentSavedForm,
) -> Result<usize, Error> {
use crate::schema::comment_saved::dsl::{comment_id, comment_saved, person_id};
use crate::schema::comment_saved::dsl::comment_saved;
let conn = &mut get_conn(pool).await?;
diesel::delete(
comment_saved
.filter(comment_id.eq(comment_saved_form.comment_id))
.filter(person_id.eq(comment_saved_form.person_id)),
comment_saved.find((comment_saved_form.person_id, comment_saved_form.comment_id)),
)
.execute(conn)
.await
@ -349,7 +343,6 @@ mod tests {
let inserted_comment_like = CommentLike::like(pool, &comment_like_form).await.unwrap();
let expected_comment_like = CommentLike {
id: inserted_comment_like.id,
comment_id: inserted_comment.id,
post_id: inserted_post.id,
person_id: inserted_person.id,
@ -366,7 +359,6 @@ mod tests {
let inserted_comment_saved = CommentSaved::save(pool, &comment_saved_form).await.unwrap();
let expected_comment_saved = CommentSaved {
id: inserted_comment_saved.id,
comment_id: inserted_comment.id,
person_id: inserted_person.id,
published: inserted_comment_saved.published,

View file

@ -95,13 +95,12 @@ impl Joinable for CommunityModerator {
pool: &mut DbPool<'_>,
community_moderator_form: &CommunityModeratorForm,
) -> Result<usize, Error> {
use crate::schema::community_moderator::dsl::{community_id, community_moderator, person_id};
use crate::schema::community_moderator::dsl::community_moderator;
let conn = &mut get_conn(pool).await?;
diesel::delete(
community_moderator
.filter(community_id.eq(community_moderator_form.community_id))
.filter(person_id.eq(community_moderator_form.person_id)),
)
diesel::delete(community_moderator.find((
community_moderator_form.person_id,
community_moderator_form.community_id,
)))
.execute(conn)
.await
}
@ -199,13 +198,12 @@ impl Bannable for CommunityPersonBan {
pool: &mut DbPool<'_>,
community_person_ban_form: &CommunityPersonBanForm,
) -> Result<usize, Error> {
use crate::schema::community_person_ban::dsl::{community_id, community_person_ban, person_id};
use crate::schema::community_person_ban::dsl::community_person_ban;
let conn = &mut get_conn(pool).await?;
diesel::delete(
community_person_ban
.filter(community_id.eq(community_person_ban_form.community_id))
.filter(person_id.eq(community_person_ban_form.person_id)),
)
diesel::delete(community_person_ban.find((
community_person_ban_form.person_id,
community_person_ban_form.community_id,
)))
.execute(conn)
.await
}
@ -274,35 +272,22 @@ impl Followable for CommunityFollower {
}
async fn follow_accepted(
pool: &mut DbPool<'_>,
community_id_: CommunityId,
person_id_: PersonId,
community_id: CommunityId,
person_id: PersonId,
) -> Result<Self, Error> {
use crate::schema::community_follower::dsl::{
community_follower,
community_id,
pending,
person_id,
};
use crate::schema::community_follower::dsl::{community_follower, pending};
let conn = &mut get_conn(pool).await?;
diesel::update(
community_follower
.filter(community_id.eq(community_id_))
.filter(person_id.eq(person_id_)),
)
.set(pending.eq(false))
.get_result::<Self>(conn)
.await
diesel::update(community_follower.find((person_id, community_id)))
.set(pending.eq(false))
.get_result::<Self>(conn)
.await
}
async fn unfollow(pool: &mut DbPool<'_>, form: &CommunityFollowerForm) -> Result<usize, Error> {
use crate::schema::community_follower::dsl::{community_follower, community_id, person_id};
use crate::schema::community_follower::dsl::community_follower;
let conn = &mut get_conn(pool).await?;
diesel::delete(
community_follower
.filter(community_id.eq(&form.community_id))
.filter(person_id.eq(&form.person_id)),
)
.execute(conn)
.await
diesel::delete(community_follower.find((form.person_id, form.community_id)))
.execute(conn)
.await
}
}
@ -448,7 +433,6 @@ mod tests {
.unwrap();
let expected_community_follower = CommunityFollower {
id: inserted_community_follower.id,
community_id: inserted_community.id,
person_id: inserted_person.id,
pending: false,
@ -465,7 +449,6 @@ mod tests {
.unwrap();
let expected_community_moderator = CommunityModerator {
id: inserted_community_moderator.id,
community_id: inserted_community.id,
person_id: inserted_person.id,
published: inserted_community_moderator.published,
@ -482,7 +465,6 @@ mod tests {
.unwrap();
let expected_community_person_ban = CommunityPersonBan {
id: inserted_community_person_ban.id,
community_id: inserted_community.id,
person_id: inserted_person.id,
published: inserted_community_person_ban.published,

View file

@ -9,7 +9,6 @@ use diesel::{
dsl::{exists, insert_into},
result::Error,
select,
ExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
@ -22,9 +21,7 @@ impl CommunityBlock {
) -> Result<bool, Error> {
let conn = &mut get_conn(pool).await?;
select(exists(
community_block
.filter(community_id.eq(for_community_id))
.filter(person_id.eq(for_person_id)),
community_block.find((for_person_id, for_community_id)),
))
.get_result(conn)
.await
@ -49,11 +46,10 @@ impl Blockable for CommunityBlock {
community_block_form: &Self::Form,
) -> Result<usize, Error> {
let conn = &mut get_conn(pool).await?;
diesel::delete(
community_block
.filter(person_id.eq(community_block_form.person_id))
.filter(community_id.eq(community_block_form.community_id)),
)
diesel::delete(community_block.find((
community_block_form.person_id,
community_block_form.community_id,
)))
.execute(conn)
.await
}

View file

@ -1,6 +1,6 @@
use crate::{
newtypes::{ImageUploadId, LocalUserId},
schema::image_upload::dsl::{image_upload, local_user_id, pictrs_alias},
newtypes::LocalUserId,
schema::image_upload::dsl::{image_upload, local_user_id},
source::image_upload::{ImageUpload, ImageUploadForm},
utils::{get_conn, DbPool},
};
@ -28,20 +28,8 @@ impl ImageUpload {
.await
}
pub async fn delete(
pool: &mut DbPool<'_>,
image_upload_id: ImageUploadId,
) -> Result<usize, Error> {
let conn = &mut get_conn(pool).await?;
diesel::delete(image_upload.find(image_upload_id))
.execute(conn)
.await
}
pub async fn delete_by_alias(pool: &mut DbPool<'_>, alias: &str) -> Result<usize, Error> {
let conn = &mut get_conn(pool).await?;
diesel::delete(image_upload.filter(pictrs_alias.eq(alias)))
.execute(conn)
.await
diesel::delete(image_upload.find(alias)).execute(conn).await
}
}

View file

@ -115,7 +115,7 @@ impl Instance {
.left_join(federation_allowlist::table)
.select((
Self::as_select(),
federation_allowlist::id.nullable().is_not_null(),
federation_allowlist::instance_id.nullable().is_not_null(),
is_dead_expr,
))
.order_by(instance::id)
@ -126,7 +126,7 @@ impl Instance {
.left_join(federation_blocklist::table)
.select((
Self::as_select(),
federation_blocklist::id.nullable().is_null(),
federation_blocklist::instance_id.nullable().is_null(),
is_dead_expr,
))
.order_by(instance::id)
@ -150,8 +150,8 @@ impl Instance {
.select((
Self::as_select(),
Option::<FederationQueueState>::as_select(),
federation_blocklist::id.nullable().is_not_null(),
federation_allowlist::id.nullable().is_not_null(),
federation_blocklist::instance_id.nullable().is_not_null(),
federation_allowlist::instance_id.nullable().is_not_null(),
))
.get_results(conn)
.await

View file

@ -9,7 +9,6 @@ use diesel::{
dsl::{exists, insert_into},
result::Error,
select,
ExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
@ -22,9 +21,7 @@ impl InstanceBlock {
) -> Result<bool, Error> {
let conn = &mut get_conn(pool).await?;
select(exists(
instance_block
.filter(instance_id.eq(for_instance_id))
.filter(person_id.eq(for_person_id)),
instance_block.find((for_person_id, for_instance_id)),
))
.get_result(conn)
.await
@ -49,11 +46,10 @@ impl Blockable for InstanceBlock {
instance_block_form: &Self::Form,
) -> Result<usize, Error> {
let conn = &mut get_conn(pool).await?;
diesel::delete(
instance_block
.filter(person_id.eq(instance_block_form.person_id))
.filter(instance_id.eq(instance_block_form.instance_id)),
)
diesel::delete(instance_block.find((
instance_block_form.person_id,
instance_block_form.instance_id,
)))
.execute(conn)
.await
}

View file

@ -1,7 +1,7 @@
use crate::{
diesel::ExpressionMethods,
newtypes::LanguageId,
schema::language::dsl::{code, id, language},
schema::language::dsl::{code, language},
source::language::Language,
utils::{get_conn, DbPool},
};
@ -16,7 +16,7 @@ impl Language {
pub async fn read_from_id(pool: &mut DbPool<'_>, id_: LanguageId) -> Result<Language, Error> {
let conn = &mut get_conn(pool).await?;
language.filter(id.eq(id_)).first::<Self>(conn).await
language.find(id_).first::<Self>(conn).await
}
/// Attempts to find the given language code and return its ID. If not found, returns none.

View file

@ -1,7 +1,7 @@
use crate::{
diesel::{ExpressionMethods, QueryDsl},
newtypes::LocalUserId,
schema::login_token::{dsl::login_token, token, user_id},
schema::login_token::{dsl::login_token, user_id},
source::login_token::{LoginToken, LoginTokenCreateForm},
utils::{get_conn, DbPool},
};
@ -25,9 +25,7 @@ impl LoginToken {
) -> Result<bool, Error> {
let conn = &mut get_conn(pool).await?;
select(exists(
login_token
.filter(user_id.eq(user_id_))
.filter(token.eq(token_)),
login_token.find(token_).filter(user_id.eq(user_id_)),
))
.get_result(conn)
.await
@ -48,9 +46,7 @@ impl LoginToken {
/// Invalidate specific token on user logout.
pub async fn invalidate(pool: &mut DbPool<'_>, token_: &str) -> Result<usize, Error> {
let conn = &mut get_conn(pool).await?;
delete(login_token.filter(token.eq(token_)))
.execute(conn)
.await
delete(login_token.find(token_)).execute(conn).await
}
/// Invalidate all logins of given user on password reset/change, account deletion or site ban.

View file

@ -155,15 +155,11 @@ impl Followable for PersonFollower {
unimplemented!()
}
async fn unfollow(pool: &mut DbPool<'_>, form: &PersonFollowerForm) -> Result<usize, Error> {
use crate::schema::person_follower::dsl::{follower_id, person_follower, person_id};
use crate::schema::person_follower::dsl::person_follower;
let conn = &mut get_conn(pool).await?;
diesel::delete(
person_follower
.filter(follower_id.eq(&form.follower_id))
.filter(person_id.eq(&form.person_id)),
)
.execute(conn)
.await
diesel::delete(person_follower.find((form.follower_id, form.person_id)))
.execute(conn)
.await
}
}

View file

@ -9,7 +9,6 @@ use diesel::{
dsl::{exists, insert_into},
result::Error,
select,
ExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
@ -21,13 +20,9 @@ impl PersonBlock {
for_recipient_id: PersonId,
) -> Result<bool, Error> {
let conn = &mut get_conn(pool).await?;
select(exists(
person_block
.filter(person_id.eq(for_person_id))
.filter(target_id.eq(for_recipient_id)),
))
.get_result(conn)
.await
select(exists(person_block.find((for_person_id, for_recipient_id))))
.get_result(conn)
.await
}
}
@ -49,12 +44,8 @@ impl Blockable for PersonBlock {
}
async fn unblock(pool: &mut DbPool<'_>, person_block_form: &Self::Form) -> Result<usize, Error> {
let conn = &mut get_conn(pool).await?;
diesel::delete(
person_block
.filter(person_id.eq(person_block_form.person_id))
.filter(target_id.eq(person_block_form.target_id)),
)
.execute(conn)
.await
diesel::delete(person_block.find((person_block_form.person_id, person_block_form.target_id)))
.execute(conn)
.await
}
}

View file

@ -266,13 +266,9 @@ impl Likeable for PostLike {
) -> Result<usize, Error> {
use crate::schema::post_like::dsl;
let conn = &mut get_conn(pool).await?;
diesel::delete(
dsl::post_like
.filter(dsl::post_id.eq(post_id))
.filter(dsl::person_id.eq(person_id)),
)
.execute(conn)
.await
diesel::delete(dsl::post_like.find((person_id, post_id)))
.execute(conn)
.await
}
}
@ -291,15 +287,11 @@ impl Saveable for PostSaved {
.await
}
async fn unsave(pool: &mut DbPool<'_>, post_saved_form: &PostSavedForm) -> Result<usize, Error> {
use crate::schema::post_saved::dsl::{person_id, post_id, post_saved};
use crate::schema::post_saved::dsl::post_saved;
let conn = &mut get_conn(pool).await?;
diesel::delete(
post_saved
.filter(post_id.eq(post_saved_form.post_id))
.filter(person_id.eq(post_saved_form.person_id)),
)
.execute(conn)
.await
diesel::delete(post_saved.find((post_saved_form.person_id, post_saved_form.post_id)))
.execute(conn)
.await
}
}
@ -444,7 +436,6 @@ mod tests {
let inserted_post_like = PostLike::like(pool, &post_like_form).await.unwrap();
let expected_post_like = PostLike {
id: inserted_post_like.id,
post_id: inserted_post.id,
person_id: inserted_person.id,
published: inserted_post_like.published,
@ -460,7 +451,6 @@ mod tests {
let inserted_post_saved = PostSaved::save(pool, &post_saved_form).await.unwrap();
let expected_post_saved = PostSaved {
id: inserted_post_saved.id,
post_id: inserted_post.id,
person_id: inserted_person.id,
published: inserted_post_saved.published,

View file

@ -83,12 +83,6 @@ pub struct PersonMentionId(i32);
/// The person block id.
pub struct PersonBlockId(i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
/// The community block id.
pub struct CommunityBlockId(i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
@ -119,30 +113,12 @@ pub struct SiteId(i32);
/// The language id.
pub struct LanguageId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct LocalUserLanguageId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct SiteLanguageId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct CommunityLanguageId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
/// The comment reply id.
pub struct CommentReplyId(i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
/// The Image Upload id.
pub struct ImageUploadId(i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]

View file

@ -65,8 +65,7 @@ diesel::table! {
}
diesel::table! {
captcha_answer (id) {
id -> Int4,
captcha_answer (uuid) {
uuid -> Uuid,
answer -> Text,
published -> Timestamptz,
@ -96,8 +95,7 @@ diesel::table! {
}
diesel::table! {
comment_aggregates (id) {
id -> Int4,
comment_aggregates (comment_id) {
comment_id -> Int4,
score -> Int8,
upvotes -> Int8,
@ -110,8 +108,7 @@ diesel::table! {
}
diesel::table! {
comment_like (id) {
id -> Int4,
comment_like (person_id, comment_id) {
person_id -> Int4,
comment_id -> Int4,
post_id -> Int4,
@ -145,8 +142,7 @@ diesel::table! {
}
diesel::table! {
comment_saved (id) {
id -> Int4,
comment_saved (person_id, comment_id) {
comment_id -> Int4,
person_id -> Int4,
published -> Timestamptz,
@ -191,8 +187,7 @@ diesel::table! {
}
diesel::table! {
community_aggregates (id) {
id -> Int4,
community_aggregates (community_id) {
community_id -> Int4,
subscribers -> Int8,
posts -> Int8,
@ -207,8 +202,7 @@ diesel::table! {
}
diesel::table! {
community_block (id) {
id -> Int4,
community_block (person_id, community_id) {
person_id -> Int4,
community_id -> Int4,
published -> Timestamptz,
@ -216,8 +210,7 @@ diesel::table! {
}
diesel::table! {
community_follower (id) {
id -> Int4,
community_follower (person_id, community_id) {
community_id -> Int4,
person_id -> Int4,
published -> Timestamptz,
@ -226,16 +219,14 @@ diesel::table! {
}
diesel::table! {
community_language (id) {
id -> Int4,
community_language (community_id, language_id) {
community_id -> Int4,
language_id -> Int4,
}
}
diesel::table! {
community_moderator (id) {
id -> Int4,
community_moderator (person_id, community_id) {
community_id -> Int4,
person_id -> Int4,
published -> Timestamptz,
@ -243,8 +234,7 @@ diesel::table! {
}
diesel::table! {
community_person_ban (id) {
id -> Int4,
community_person_ban (person_id, community_id) {
community_id -> Int4,
person_id -> Int4,
published -> Timestamptz,
@ -267,8 +257,7 @@ diesel::table! {
}
diesel::table! {
custom_emoji_keyword (id) {
id -> Int4,
custom_emoji_keyword (custom_emoji_id, keyword) {
custom_emoji_id -> Int4,
#[max_length = 128]
keyword -> Varchar,
@ -286,8 +275,7 @@ diesel::table! {
}
diesel::table! {
federation_allowlist (id) {
id -> Int4,
federation_allowlist (instance_id) {
instance_id -> Int4,
published -> Timestamptz,
updated -> Nullable<Timestamptz>,
@ -295,8 +283,7 @@ diesel::table! {
}
diesel::table! {
federation_blocklist (id) {
id -> Int4,
federation_blocklist (instance_id) {
instance_id -> Int4,
published -> Timestamptz,
updated -> Nullable<Timestamptz>,
@ -304,8 +291,7 @@ diesel::table! {
}
diesel::table! {
federation_queue_state (id) {
id -> Int4,
federation_queue_state (instance_id) {
instance_id -> Int4,
last_successful_id -> Nullable<Int8>,
fail_count -> Int4,
@ -315,8 +301,7 @@ diesel::table! {
}
diesel::table! {
image_upload (id) {
id -> Int4,
image_upload (pictrs_alias) {
local_user_id -> Int4,
pictrs_alias -> Text,
pictrs_delete_token -> Text,
@ -339,8 +324,7 @@ diesel::table! {
}
diesel::table! {
instance_block (id) {
id -> Int4,
instance_block (person_id, instance_id) {
person_id -> Int4,
instance_id -> Int4,
published -> Timestamptz,
@ -391,8 +375,7 @@ diesel::table! {
}
diesel::table! {
local_site_rate_limit (id) {
id -> Int4,
local_site_rate_limit (local_site_id) {
local_site_id -> Int4,
message -> Int4,
message_per_second -> Int4,
@ -452,16 +435,14 @@ diesel::table! {
}
diesel::table! {
local_user_language (id) {
id -> Int4,
local_user_language (local_user_id, language_id) {
local_user_id -> Int4,
language_id -> Int4,
}
}
diesel::table! {
login_token (id) {
id -> Int4,
login_token (token) {
token -> Text,
user_id -> Int4,
published -> Timestamptz,
@ -632,8 +613,7 @@ diesel::table! {
}
diesel::table! {
person_aggregates (id) {
id -> Int4,
person_aggregates (person_id) {
person_id -> Int4,
post_count -> Int8,
post_score -> Int8,
@ -643,16 +623,14 @@ diesel::table! {
}
diesel::table! {
person_ban (id) {
id -> Int4,
person_ban (person_id) {
person_id -> Int4,
published -> Timestamptz,
}
}
diesel::table! {
person_block (id) {
id -> Int4,
person_block (person_id, target_id) {
person_id -> Int4,
target_id -> Int4,
published -> Timestamptz,
@ -660,8 +638,7 @@ diesel::table! {
}
diesel::table! {
person_follower (id) {
id -> Int4,
person_follower (follower_id, person_id) {
person_id -> Int4,
follower_id -> Int4,
published -> Timestamptz,
@ -680,8 +657,7 @@ diesel::table! {
}
diesel::table! {
person_post_aggregates (id) {
id -> Int4,
person_post_aggregates (person_id, post_id) {
person_id -> Int4,
post_id -> Int4,
read_comments -> Int8,
@ -719,8 +695,7 @@ diesel::table! {
}
diesel::table! {
post_aggregates (id) {
id -> Int4,
post_aggregates (post_id) {
post_id -> Int4,
comments -> Int8,
score -> Int8,
@ -742,8 +717,7 @@ diesel::table! {
}
diesel::table! {
post_like (id) {
id -> Int4,
post_like (person_id, post_id) {
post_id -> Int4,
person_id -> Int4,
score -> Int2,
@ -752,8 +726,7 @@ diesel::table! {
}
diesel::table! {
post_read (id) {
id -> Int4,
post_read (person_id, post_id) {
post_id -> Int4,
person_id -> Int4,
published -> Timestamptz,
@ -778,8 +751,7 @@ diesel::table! {
}
diesel::table! {
post_saved (id) {
id -> Int4,
post_saved (person_id, post_id) {
post_id -> Int4,
person_id -> Int4,
published -> Timestamptz,
@ -817,8 +789,7 @@ diesel::table! {
}
diesel::table! {
received_activity (id) {
id -> Int8,
received_activity (ap_id) {
ap_id -> Text,
published -> Timestamptz,
}
@ -884,8 +855,7 @@ diesel::table! {
}
diesel::table! {
site_aggregates (id) {
id -> Int4,
site_aggregates (site_id) {
site_id -> Int4,
users -> Int8,
posts -> Int8,
@ -899,8 +869,7 @@ diesel::table! {
}
diesel::table! {
site_language (id) {
id -> Int4,
site_language (site_id, language_id) {
site_id -> Int4,
language_id -> Int4,
}

View file

@ -1,12 +1,4 @@
use crate::newtypes::{
CommunityId,
CommunityLanguageId,
LanguageId,
LocalUserId,
LocalUserLanguageId,
SiteId,
SiteLanguageId,
};
use crate::newtypes::{CommunityId, LanguageId, LocalUserId, SiteId};
#[cfg(feature = "full")]
use crate::schema::local_user_language;
use serde::{Deserialize, Serialize};
@ -14,9 +6,8 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
#[cfg_attr(feature = "full", diesel(table_name = local_user_language))]
#[cfg_attr(feature = "full", diesel(primary_key(local_user_id, language_id)))]
pub struct LocalUserLanguage {
#[serde(skip)]
pub id: LocalUserLanguageId,
pub local_user_id: LocalUserId,
pub language_id: LanguageId,
}
@ -35,9 +26,8 @@ use crate::schema::community_language;
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
#[cfg_attr(feature = "full", diesel(table_name = community_language))]
#[cfg_attr(feature = "full", diesel(primary_key(community_id, language_id)))]
pub struct CommunityLanguage {
#[serde(skip)]
pub id: CommunityLanguageId,
pub community_id: CommunityId,
pub language_id: LanguageId,
}
@ -56,9 +46,8 @@ use crate::schema::site_language;
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
#[cfg_attr(feature = "full", diesel(table_name = site_language))]
#[cfg_attr(feature = "full", diesel(primary_key(site_id, language_id)))]
pub struct SiteLanguage {
#[serde(skip)]
pub id: SiteLanguageId,
pub site_id: SiteId,
pub language_id: LanguageId,
}

View file

@ -10,7 +10,6 @@ use uuid::Uuid;
#[cfg_attr(feature = "full", derive(Queryable))]
#[cfg_attr(feature = "full", diesel(table_name = captcha_answer))]
pub struct CaptchaAnswer {
pub id: i32,
pub uuid: Uuid,
pub answer: String,
pub published: DateTime<Utc>,

View file

@ -86,8 +86,8 @@ pub struct CommentUpdateForm {
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
#[cfg_attr(feature = "full", diesel(table_name = comment_like))]
#[cfg_attr(feature = "full", diesel(primary_key(person_id, comment_id)))]
pub struct CommentLike {
pub id: i32,
pub person_id: PersonId,
pub comment_id: CommentId,
pub post_id: PostId, // TODO this is redundant
@ -109,8 +109,8 @@ pub struct CommentLikeForm {
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
#[cfg_attr(feature = "full", diesel(table_name = comment_saved))]
#[cfg_attr(feature = "full", diesel(primary_key(person_id, comment_id)))]
pub struct CommentSaved {
pub id: i32,
pub comment_id: CommentId,
pub person_id: PersonId,
pub published: DateTime<Utc>,

View file

@ -134,8 +134,8 @@ pub struct CommunityUpdateForm {
diesel(belongs_to(crate::source::community::Community))
)]
#[cfg_attr(feature = "full", diesel(table_name = community_moderator))]
#[cfg_attr(feature = "full", diesel(primary_key(person_id, community_id)))]
pub struct CommunityModerator {
pub id: i32,
pub community_id: CommunityId,
pub person_id: PersonId,
pub published: DateTime<Utc>,
@ -156,8 +156,8 @@ pub struct CommunityModeratorForm {
diesel(belongs_to(crate::source::community::Community))
)]
#[cfg_attr(feature = "full", diesel(table_name = community_person_ban))]
#[cfg_attr(feature = "full", diesel(primary_key(person_id, community_id)))]
pub struct CommunityPersonBan {
pub id: i32,
pub community_id: CommunityId,
pub person_id: PersonId,
pub published: DateTime<Utc>,
@ -180,8 +180,8 @@ pub struct CommunityPersonBanForm {
diesel(belongs_to(crate::source::community::Community))
)]
#[cfg_attr(feature = "full", diesel(table_name = community_follower))]
#[cfg_attr(feature = "full", diesel(primary_key(person_id, community_id)))]
pub struct CommunityFollower {
pub id: i32,
pub community_id: CommunityId,
pub person_id: PersonId,
pub published: DateTime<Utc>,

View file

@ -1,4 +1,4 @@
use crate::newtypes::{CommunityBlockId, CommunityId, PersonId};
use crate::newtypes::{CommunityId, PersonId};
#[cfg(feature = "full")]
use crate::schema::community_block;
use chrono::{DateTime, Utc};
@ -11,8 +11,8 @@ use serde::{Deserialize, Serialize};
diesel(belongs_to(crate::source::community::Community))
)]
#[cfg_attr(feature = "full", diesel(table_name = community_block))]
#[cfg_attr(feature = "full", diesel(primary_key(person_id, community_id)))]
pub struct CommunityBlock {
pub id: CommunityBlockId,
pub person_id: PersonId,
pub community_id: CommunityId,
pub published: DateTime<Utc>,

View file

@ -13,10 +13,10 @@ use typed_builder::TypedBuilder;
feature = "full",
diesel(belongs_to(crate::source::custom_emoji::CustomEmoji))
)]
#[cfg_attr(feature = "full", diesel(primary_key(custom_emoji_id, keyword)))]
#[cfg_attr(feature = "full", ts(export))]
/// A custom keyword for an emoji.
pub struct CustomEmojiKeyword {
pub id: i32,
pub custom_emoji_id: CustomEmojiId,
pub keyword: String,
}

View file

@ -12,8 +12,8 @@ use std::fmt::Debug;
diesel(belongs_to(crate::source::instance::Instance))
)]
#[cfg_attr(feature = "full", diesel(table_name = federation_allowlist))]
#[cfg_attr(feature = "full", diesel(primary_key(instance_id)))]
pub struct FederationAllowList {
pub id: i32,
pub instance_id: InstanceId,
pub published: DateTime<Utc>,
pub updated: Option<DateTime<Utc>>,

View file

@ -12,8 +12,8 @@ use std::fmt::Debug;
diesel(belongs_to(crate::source::instance::Instance))
)]
#[cfg_attr(feature = "full", diesel(table_name = federation_blocklist))]
#[cfg_attr(feature = "full", diesel(primary_key(instance_id)))]
pub struct FederationBlockList {
pub id: i32,
pub instance_id: InstanceId,
pub published: DateTime<Utc>,
pub updated: Option<DateTime<Utc>>,

View file

@ -1,4 +1,4 @@
use crate::newtypes::{ImageUploadId, LocalUserId};
use crate::newtypes::LocalUserId;
#[cfg(feature = "full")]
use crate::schema::image_upload;
use chrono::{DateTime, Utc};
@ -13,13 +13,13 @@ use typed_builder::TypedBuilder;
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
#[cfg_attr(feature = "full", diesel(table_name = image_upload))]
#[cfg_attr(feature = "full", diesel(primary_key(pictrs_alias)))]
#[cfg_attr(feature = "full", ts(export))]
#[cfg_attr(
feature = "full",
diesel(belongs_to(crate::source::local_user::LocalUser))
)]
pub struct ImageUpload {
pub id: ImageUploadId,
pub local_user_id: LocalUserId,
pub pictrs_alias: String,
pub pictrs_delete_token: String,

View file

@ -11,8 +11,8 @@ use serde::{Deserialize, Serialize};
diesel(belongs_to(crate::source::instance::Instance))
)]
#[cfg_attr(feature = "full", diesel(table_name = instance_block))]
#[cfg_attr(feature = "full", diesel(primary_key(person_id, instance_id)))]
pub struct InstanceBlock {
pub id: i32,
pub person_id: PersonId,
pub instance_id: InstanceId,
pub published: DateTime<Utc>,

View file

@ -12,6 +12,7 @@ use typed_builder::TypedBuilder;
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "full", derive(Queryable, Identifiable, TS))]
#[cfg_attr(feature = "full", diesel(table_name = local_site_rate_limit))]
#[cfg_attr(feature = "full", diesel(primary_key(local_site_id)))]
#[cfg_attr(
feature = "full",
diesel(belongs_to(crate::source::local_site::LocalSite))
@ -19,7 +20,6 @@ use typed_builder::TypedBuilder;
#[cfg_attr(feature = "full", ts(export))]
/// Rate limits for your site. Given in count / length of time.
pub struct LocalSiteRateLimit {
pub id: i32,
pub local_site_id: LocalSiteId,
pub message: i32,
pub message_per_second: i32,

View file

@ -12,9 +12,9 @@ use ts_rs::TS;
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "full", derive(Queryable, Identifiable, TS))]
#[cfg_attr(feature = "full", diesel(table_name = login_token))]
#[cfg_attr(feature = "full", diesel(primary_key(token)))]
#[cfg_attr(feature = "full", ts(export))]
pub struct LoginToken {
pub id: i32,
/// Jwt token for this login
#[serde(skip)]
pub token: String,

View file

@ -115,8 +115,8 @@ pub struct PersonUpdateForm {
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::person::Person)))]
#[cfg_attr(feature = "full", diesel(table_name = person_follower))]
#[cfg_attr(feature = "full", diesel(primary_key(follower_id, person_id)))]
pub struct PersonFollower {
pub id: i32,
pub person_id: PersonId,
pub follower_id: PersonId,
pub published: DateTime<Utc>,

View file

@ -1,4 +1,4 @@
use crate::newtypes::{PersonBlockId, PersonId};
use crate::newtypes::PersonId;
#[cfg(feature = "full")]
use crate::schema::person_block;
use chrono::{DateTime, Utc};
@ -8,8 +8,8 @@ use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::person::Person)))]
#[cfg_attr(feature = "full", diesel(table_name = person_block))]
#[cfg_attr(feature = "full", diesel(primary_key(person_id, target_id)))]
pub struct PersonBlock {
pub id: PersonBlockId,
pub person_id: PersonId,
pub target_id: PersonId,
pub published: DateTime<Utc>,

View file

@ -114,8 +114,8 @@ pub struct PostUpdateForm {
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::post::Post)))]
#[cfg_attr(feature = "full", diesel(table_name = post_like))]
#[cfg_attr(feature = "full", diesel(primary_key(person_id, post_id)))]
pub struct PostLike {
pub id: i32,
pub post_id: PostId,
pub person_id: PersonId,
pub score: i16,
@ -135,8 +135,8 @@ pub struct PostLikeForm {
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::post::Post)))]
#[cfg_attr(feature = "full", diesel(table_name = post_saved))]
#[cfg_attr(feature = "full", diesel(primary_key(post_id, person_id)))]
pub struct PostSaved {
pub id: i32,
pub post_id: PostId,
pub person_id: PersonId,
pub published: DateTime<Utc>,

View file

@ -62,7 +62,7 @@ fn queries<'a>() -> Queries<
person::all_columns,
aliases::person1.fields(person::all_columns),
comment_aggregates::all_columns,
community_person_ban::id.nullable().is_not_null(),
community_person_ban::community_id.nullable().is_not_null(),
comment_like::score.nullable(),
aliases::person2.fields(person::all_columns).nullable(),
);
@ -425,7 +425,6 @@ mod tests {
},
creator_banned_from_community: false,
counts: CommentAggregates {
id: agg.id,
comment_id: inserted_comment.id,
score: 0,
upvotes: 0,

View file

@ -110,14 +110,14 @@ fn queries<'a>() -> Queries<
post::all_columns,
community::all_columns,
comment_aggregates::all_columns,
community_person_ban::id.nullable().is_not_null(),
community_person_ban::community_id.nullable().is_not_null(),
aliases::community_moderator1
.field(community_moderator::id)
.field(community_moderator::community_id)
.nullable()
.is_not_null(),
CommunityFollower::select_subscribed_type(),
comment_saved::id.nullable().is_not_null(),
person_block::id.nullable().is_not_null(),
comment_saved::comment_id.nullable().is_not_null(),
person_block::person_id.nullable().is_not_null(),
comment_like::score.nullable(),
);
@ -509,7 +509,6 @@ mod tests {
.unwrap();
let expected_block = PersonBlock {
id: inserted_block.id,
person_id: inserted_person.id,
target_id: inserted_person_2.id,
published: inserted_block.published,
@ -947,7 +946,6 @@ mod tests {
featured_url: data.inserted_community.featured_url.clone(),
},
counts: CommentAggregates {
id: agg.id,
comment_id: data.inserted_comment_0.id,
score: 1,
upvotes: 1,

View file

@ -60,7 +60,7 @@ fn queries<'a>() -> Queries<
community::all_columns,
person::all_columns,
aliases::person1.fields(person::all_columns),
community_person_ban::id.nullable().is_not_null(),
community_person_ban::community_id.nullable().is_not_null(),
post_like::score.nullable(),
post_aggregates::all_columns,
aliases::person2.fields(person::all_columns.nullable()),

View file

@ -995,7 +995,6 @@ mod tests {
let inserted_post_like = PostLike::like(pool, &post_like_form).await.unwrap();
let expected_post_like = PostLike {
id: inserted_post_like.id,
post_id: data.inserted_post.id,
person_id: data.local_user_view.person.id,
published: inserted_post_like.published,
@ -1462,7 +1461,6 @@ mod tests {
featured_url: inserted_community.featured_url.clone(),
},
counts: PostAggregates {
id: agg.id,
post_id: inserted_post.id,
comments: 0,
score: 0,

View file

@ -312,7 +312,6 @@ mod tests {
.unwrap();
let expected_block = PersonBlock {
id: inserted_block.id,
person_id: timmy.id,
target_id: sara.id,
published: inserted_block.published,

View file

@ -96,11 +96,11 @@ fn queries<'a>() -> Queries<
community::all_columns,
aliases::person1.fields(person::all_columns),
comment_aggregates::all_columns,
community_person_ban::id.nullable().is_not_null(),
community_moderator::id.nullable().is_not_null(),
community_person_ban::community_id.nullable().is_not_null(),
community_moderator::community_id.nullable().is_not_null(),
CommunityFollower::select_subscribed_type(),
comment_saved::id.nullable().is_not_null(),
person_block::id.nullable().is_not_null(),
comment_saved::comment_id.nullable().is_not_null(),
person_block::person_id.nullable().is_not_null(),
comment_like::score.nullable(),
))
};

View file

@ -62,7 +62,7 @@ fn queries<'a>() -> Queries<
let selection = (
community::all_columns,
CommunityFollower::select_subscribed_type(),
community_block::id.nullable().is_not_null(),
community_block::community_id.nullable().is_not_null(),
community_aggregates::all_columns,
);

View file

@ -85,11 +85,11 @@ fn queries<'a>() -> Queries<
community::all_columns,
aliases::person1.fields(person::all_columns),
comment_aggregates::all_columns,
community_person_ban::id.nullable().is_not_null(),
community_moderator::id.nullable().is_not_null(),
community_person_ban::community_id.nullable().is_not_null(),
community_moderator::community_id.nullable().is_not_null(),
CommunityFollower::select_subscribed_type(),
comment_saved::id.nullable().is_not_null(),
person_block::id.nullable().is_not_null(),
comment_saved::comment_id.nullable().is_not_null(),
person_block::person_id.nullable().is_not_null(),
comment_like::score.nullable(),
);

View file

@ -0,0 +1,191 @@
ALTER TABLE captcha_answer
ADD UNIQUE (uuid),
DROP CONSTRAINT captcha_answer_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE comment_aggregates
ADD UNIQUE (comment_id),
DROP CONSTRAINT comment_aggregates_pkey,
ADD COLUMN id serial PRIMARY KEY;
CREATE INDEX idx_comment_like_person ON comment_like (person_id);
ALTER TABLE comment_like
ADD UNIQUE (comment_id, person_id),
DROP CONSTRAINT comment_like_pkey,
ADD COLUMN id serial PRIMARY KEY;
CREATE INDEX idx_comment_saved_person_id ON comment_saved (person_id);
ALTER TABLE comment_saved
ADD UNIQUE (comment_id, person_id),
DROP CONSTRAINT comment_saved_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE community_aggregates
ADD UNIQUE (community_id),
DROP CONSTRAINT community_aggregates_pkey,
ADD COLUMN id serial PRIMARY KEY;
CREATE INDEX idx_community_block_person ON community_block (person_id);
ALTER TABLE community_block
ADD UNIQUE (person_id, community_id),
DROP CONSTRAINT community_block_pkey,
ADD COLUMN id serial PRIMARY KEY;
CREATE INDEX idx_community_follower_person ON community_follower (person_id);
ALTER TABLE community_follower
ADD UNIQUE (community_id, person_id),
DROP CONSTRAINT community_follower_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE community_language
ADD UNIQUE (community_id, language_id),
DROP CONSTRAINT community_language_pkey,
ADD COLUMN id serial PRIMARY KEY;
CREATE INDEX idx_community_moderator_person ON community_moderator (person_id);
ALTER TABLE community_moderator
ADD UNIQUE (community_id, person_id),
DROP CONSTRAINT community_moderator_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE community_person_ban
ADD UNIQUE (community_id, person_id),
DROP CONSTRAINT community_person_ban_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE custom_emoji_keyword
ADD UNIQUE (custom_emoji_id, keyword),
DROP CONSTRAINT custom_emoji_keyword_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE federation_allowlist
ADD UNIQUE (instance_id),
DROP CONSTRAINT federation_allowlist_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE federation_blocklist
ADD UNIQUE (instance_id),
DROP CONSTRAINT federation_blocklist_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE federation_queue_state
ADD UNIQUE (instance_id),
DROP CONSTRAINT federation_queue_state_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE image_upload
ADD UNIQUE (pictrs_alias),
DROP CONSTRAINT image_upload_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE instance_block
ADD UNIQUE (person_id, instance_id),
DROP CONSTRAINT instance_block_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE local_site_rate_limit
ADD UNIQUE (local_site_id),
DROP CONSTRAINT local_site_rate_limit_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE local_user_language
ADD UNIQUE (local_user_id, language_id),
DROP CONSTRAINT local_user_language_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE login_token
ADD UNIQUE (token),
DROP CONSTRAINT login_token_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE person_aggregates
ADD UNIQUE (person_id),
DROP CONSTRAINT person_aggregates_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE person_ban
ADD UNIQUE (person_id),
DROP CONSTRAINT person_ban_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE person_block
ADD UNIQUE (person_id, target_id),
DROP CONSTRAINT person_block_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE person_follower
ADD UNIQUE (follower_id, person_id),
DROP CONSTRAINT person_follower_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE person_post_aggregates
ADD UNIQUE (person_id, post_id),
DROP CONSTRAINT person_post_aggregates_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE post_aggregates
ADD UNIQUE (post_id),
DROP CONSTRAINT post_aggregates_pkey,
ADD COLUMN id serial PRIMARY KEY;
CREATE INDEX idx_post_like_person ON post_like (person_id);
ALTER TABLE post_like
ADD UNIQUE (post_id, person_id),
DROP CONSTRAINT post_like_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE post_read
ADD UNIQUE (post_id, person_id),
DROP CONSTRAINT post_read_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE received_activity
ADD UNIQUE (ap_id),
DROP CONSTRAINT received_activity_pkey,
ADD COLUMN id serial PRIMARY KEY;
CREATE INDEX idx_post_saved_person_id ON post_saved (person_id);
ALTER TABLE post_saved
ADD UNIQUE (post_id, person_id),
DROP CONSTRAINT post_saved_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE site_aggregates
DROP CONSTRAINT site_aggregates_pkey,
ADD COLUMN id serial PRIMARY KEY;
ALTER TABLE site_language
ADD UNIQUE (site_id, language_id),
DROP CONSTRAINT site_language_pkey,
ADD COLUMN id serial PRIMARY KEY;
CREATE OR REPLACE FUNCTION site_aggregates_site ()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
-- we only ever want to have a single value in site_aggregate because the site_aggregate triggers update all rows in that table.
-- a cleaner check would be to insert it for the local_site but that would break assumptions at least in the tests
IF (TG_OP = 'INSERT') AND NOT EXISTS (
SELECT
id
FROM
site_aggregates
LIMIT 1) THEN
INSERT INTO site_aggregates (site_id)
VALUES (NEW.id);
ELSIF (TG_OP = 'DELETE') THEN
DELETE FROM site_aggregates
WHERE site_id = OLD.id;
END IF;
RETURN NULL;
END
$$;

View file

@ -0,0 +1,228 @@
ALTER TABLE captcha_answer
DROP COLUMN id,
ADD PRIMARY KEY (uuid),
DROP CONSTRAINT captcha_answer_uuid_key;
ALTER TABLE comment_aggregates
DROP COLUMN id,
ADD PRIMARY KEY (comment_id),
DROP CONSTRAINT comment_aggregates_comment_id_key;
ALTER TABLE comment_like
DROP COLUMN id,
ADD PRIMARY KEY (person_id, comment_id),
DROP CONSTRAINT comment_like_comment_id_person_id_key;
DROP INDEX idx_comment_like_person;
ALTER TABLE comment_saved
DROP COLUMN id,
ADD PRIMARY KEY (person_id, comment_id),
DROP CONSTRAINT comment_saved_comment_id_person_id_key;
DROP INDEX idx_comment_saved_person_id;
ALTER TABLE community_aggregates
DROP COLUMN id,
ADD PRIMARY KEY (community_id),
DROP CONSTRAINT community_aggregates_community_id_key;
ALTER TABLE community_block
DROP COLUMN id,
ADD PRIMARY KEY (person_id, community_id),
DROP CONSTRAINT community_block_person_id_community_id_key;
DROP INDEX idx_community_block_person;
ALTER TABLE community_follower
DROP COLUMN id,
ADD PRIMARY KEY (person_id, community_id),
DROP CONSTRAINT community_follower_community_id_person_id_key;
DROP INDEX idx_community_follower_person;
ALTER TABLE community_language
DROP COLUMN id,
ADD PRIMARY KEY (community_id, language_id),
DROP CONSTRAINT community_language_community_id_language_id_key;
ALTER TABLE community_moderator
DROP COLUMN id,
ADD PRIMARY KEY (person_id, community_id),
DROP CONSTRAINT community_moderator_community_id_person_id_key;
DROP INDEX idx_community_moderator_person;
ALTER TABLE community_person_ban
DROP COLUMN id,
ADD PRIMARY KEY (person_id, community_id),
DROP CONSTRAINT community_person_ban_community_id_person_id_key;
ALTER TABLE custom_emoji_keyword
DROP COLUMN id,
ADD PRIMARY KEY (custom_emoji_id, keyword),
DROP CONSTRAINT custom_emoji_keyword_custom_emoji_id_keyword_key;
ALTER TABLE federation_allowlist
DROP COLUMN id,
ADD PRIMARY KEY (instance_id),
DROP CONSTRAINT federation_allowlist_instance_id_key;
ALTER TABLE federation_blocklist
DROP COLUMN id,
ADD PRIMARY KEY (instance_id),
DROP CONSTRAINT federation_blocklist_instance_id_key;
ALTER TABLE federation_queue_state
DROP COLUMN id,
ADD PRIMARY KEY (instance_id),
DROP CONSTRAINT federation_queue_state_instance_id_key;
ALTER TABLE image_upload
DROP COLUMN id,
ADD PRIMARY KEY (pictrs_alias),
DROP CONSTRAINT image_upload_pictrs_alias_key;
ALTER TABLE instance_block
DROP COLUMN id,
ADD PRIMARY KEY (person_id, instance_id),
DROP CONSTRAINT instance_block_person_id_instance_id_key;
ALTER TABLE local_site_rate_limit
DROP COLUMN id,
ADD PRIMARY KEY (local_site_id),
DROP CONSTRAINT local_site_rate_limit_local_site_id_key;
ALTER TABLE local_user_language
DROP COLUMN id,
ADD PRIMARY KEY (local_user_id, language_id),
DROP CONSTRAINT local_user_language_local_user_id_language_id_key;
ALTER TABLE login_token
DROP COLUMN id,
ADD PRIMARY KEY (token),
DROP CONSTRAINT login_token_token_key;
-- Delete duplicates which can exist because of missing `UNIQUE` constraint
DELETE FROM person_aggregates AS a USING (
SELECT
min(id) AS id,
person_id
FROM
person_aggregates
GROUP BY
person_id
HAVING
count(*) > 1) AS b
WHERE
a.person_id = b.person_id
AND a.id != b.id;
ALTER TABLE person_aggregates
DROP CONSTRAINT IF EXISTS person_aggregates_person_id_key;
ALTER TABLE person_aggregates
ADD UNIQUE (person_id);
ALTER TABLE person_aggregates
DROP COLUMN id,
ADD PRIMARY KEY (person_id),
DROP CONSTRAINT person_aggregates_person_id_key;
ALTER TABLE person_ban
DROP COLUMN id,
ADD PRIMARY KEY (person_id),
DROP CONSTRAINT person_ban_person_id_key;
ALTER TABLE person_block
DROP COLUMN id,
ADD PRIMARY KEY (person_id, target_id),
DROP CONSTRAINT person_block_person_id_target_id_key;
ALTER TABLE person_follower
DROP COLUMN id,
ADD PRIMARY KEY (follower_id, person_id),
DROP CONSTRAINT person_follower_follower_id_person_id_key;
ALTER TABLE person_post_aggregates
DROP COLUMN id,
ADD PRIMARY KEY (person_id, post_id),
DROP CONSTRAINT person_post_aggregates_person_id_post_id_key;
ALTER TABLE post_aggregates
DROP COLUMN id,
ADD PRIMARY KEY (post_id),
DROP CONSTRAINT post_aggregates_post_id_key;
ALTER TABLE post_like
DROP COLUMN id,
ADD PRIMARY KEY (person_id, post_id),
DROP CONSTRAINT post_like_post_id_person_id_key;
DROP INDEX idx_post_like_person;
ALTER TABLE post_read
DROP COLUMN id,
ADD PRIMARY KEY (person_id, post_id),
DROP CONSTRAINT post_read_post_id_person_id_key;
ALTER TABLE post_saved
DROP COLUMN id,
ADD PRIMARY KEY (person_id, post_id),
DROP CONSTRAINT post_saved_post_id_person_id_key;
DROP INDEX idx_post_saved_person_id;
ALTER TABLE received_activity
DROP COLUMN id,
ADD PRIMARY KEY (ap_id),
DROP CONSTRAINT received_activity_ap_id_key;
-- Delete duplicates which can exist because of missing `UNIQUE` constraint
DELETE FROM site_aggregates AS a USING (
SELECT
min(id) AS id,
site_id
FROM
site_aggregates
GROUP BY
site_id
HAVING
count(*) > 1) AS b
WHERE
a.site_id = b.site_id
AND a.id != b.id;
ALTER TABLE site_aggregates
DROP COLUMN id,
ADD PRIMARY KEY (site_id);
ALTER TABLE site_language
DROP COLUMN id,
ADD PRIMARY KEY (site_id, language_id),
DROP CONSTRAINT site_language_site_id_language_id_key;
-- Change functions to not use the removed columns
CREATE OR REPLACE FUNCTION site_aggregates_site ()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
-- we only ever want to have a single value in site_aggregate because the site_aggregate triggers update all rows in that table.
-- a cleaner check would be to insert it for the local_site but that would break assumptions at least in the tests
IF (TG_OP = 'INSERT') AND NOT EXISTS (
SELECT
*
FROM
site_aggregates
LIMIT 1) THEN
INSERT INTO site_aggregates (site_id)
VALUES (NEW.id);
ELSIF (TG_OP = 'DELETE') THEN
DELETE FROM site_aggregates
WHERE site_id = OLD.id;
END IF;
RETURN NULL;
END
$$;

View file

@ -130,7 +130,7 @@ async fn update_hot_ranks(pool: &mut DbPool<'_>) {
process_ranks_in_batches(
&mut conn,
"comment_aggregates",
"comment",
"a.hot_rank != 0",
"SET hot_rank = hot_rank(a.score, a.published)",
)
@ -138,7 +138,7 @@ async fn update_hot_ranks(pool: &mut DbPool<'_>) {
process_ranks_in_batches(
&mut conn,
"community_aggregates",
"community",
"a.hot_rank != 0",
"SET hot_rank = hot_rank(a.subscribers, a.published)",
)
@ -180,16 +180,17 @@ async fn process_ranks_in_batches(
// Raw `sql_query` is used as a performance optimization - Diesel does not support doing this
// in a single query (neither as a CTE, nor using a subquery)
let result = sql_query(format!(
r#"WITH batch AS (SELECT a.id
r#"WITH batch AS (SELECT a.{id_column}
FROM {aggregates_table} a
WHERE a.published > $1 AND ({where_clause})
ORDER BY a.published
LIMIT $2
FOR UPDATE SKIP LOCKED)
UPDATE {aggregates_table} a {set_clause}
FROM batch WHERE a.id = batch.id RETURNING a.published;
FROM batch WHERE a.{id_column} = batch.{id_column} RETURNING a.published;
"#,
aggregates_table = table_name,
id_column = format!("{table_name}_id"),
aggregates_table = format!("{table_name}_aggregates"),
set_clause = set_clause,
where_clause = where_clause
))
@ -228,7 +229,7 @@ async fn process_post_aggregates_ranks_in_batches(conn: &mut AsyncPgConnection)
let mut previous_batch_result = Some(process_start_time);
while let Some(previous_batch_last_published) = previous_batch_result {
let result = sql_query(
r#"WITH batch AS (SELECT pa.id
r#"WITH batch AS (SELECT pa.post_id
FROM post_aggregates pa
WHERE pa.published > $1
AND (pa.hot_rank != 0 OR pa.hot_rank_active != 0)
@ -240,7 +241,7 @@ async fn process_post_aggregates_ranks_in_batches(conn: &mut AsyncPgConnection)
hot_rank_active = hot_rank(pa.score, pa.newest_comment_time_necro),
scaled_rank = scaled_rank(pa.score, pa.published, ca.users_active_month)
FROM batch, community_aggregates ca
WHERE pa.id = batch.id and pa.community_id = ca.community_id RETURNING pa.published;
WHERE pa.post_id = batch.post_id and pa.community_id = ca.community_id RETURNING pa.published;
"#,
)
.bind::<Timestamptz, _>(previous_batch_last_published)