Remove left joins and use only one call to select method in post_view.rs (#3865)

* Use same joins for read and list in post_view.rs

* fmt

* rerun ci

* rerun ci

* Update post_view.rs

* rerun ci

* rerun ci

* Update post_view.rs

* Use `exists`

* Update post_view.rs

* Update post_view.rs

* Update post_view.rs

* rerun ci

* Update post_view.rs

* person_id_join parameter

* rerun ci

* fmt

* Update post_view.rs

* rerun ci

* Update post_view.rs

* rerun ci

* fmt

* Update post_view.rs

* fmt

* Use into_sql

* Update post_view.rs

* Use inferred query source for BoxableExpression

* Update post_view.rs

* Update post_view.rs

* Update community.rs

* Update community.rs

* Update post_view.rs

* fmt

* Update community.rs

* Update community.rs

* Update community.rs

* Update community.rs

* Update community.rs

* Update post_view.rs

* Update community.rs

* fmt

* Update post_view.rs

* Update post_view.rs

* Update post_view.rs

* Update post_view.rs

* Update post_view.rs

* Update post_view.rs

* Update post_view.rs

* fmt

* Update post_view.rs

* Update post_view.rs

* fix

* trigger ci

---------

Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
Co-authored-by: phiresky <phireskyde+git@gmail.com>
use_person_id_for_add_admin
dullbananas 2023-09-04 02:05:00 -07:00 committed by GitHub
parent a57658d99c
commit 5b5ac0f37d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 191 additions and 127 deletions

View File

@ -1,15 +1,15 @@
use crate::structs::{LocalUserView, PostView}; use crate::structs::{LocalUserView, PostView};
use diesel::{ use diesel::{
debug_query, debug_query,
dsl::IntervalDsl, dsl::{exists, not, IntervalDsl},
pg::Pg, pg::Pg,
result::Error, result::Error,
sql_function, sql_function,
sql_types::{self, Timestamptz}, sql_types::{self, Timestamptz},
BoolExpressionMethods, BoolExpressionMethods,
BoxableExpression,
ExpressionMethods, ExpressionMethods,
IntoSql, IntoSql,
JoinOnDsl,
NullableExpressionMethods, NullableExpressionMethods,
PgTextExpressionMethods, PgTextExpressionMethods,
QueryDsl, QueryDsl,
@ -33,7 +33,6 @@ use lemmy_db_schema::{
post_read, post_read,
post_saved, post_saved,
}, },
source::community::CommunityFollower,
utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
ListingType, ListingType,
SortType, SortType,
@ -46,88 +45,144 @@ fn queries<'a>() -> Queries<
impl ReadFn<'a, PostView, (PostId, Option<PersonId>, bool)>, impl ReadFn<'a, PostView, (PostId, Option<PersonId>, bool)>,
impl ListFn<'a, PostView, PostQuery<'a>>, impl ListFn<'a, PostView, PostQuery<'a>>,
> { > {
let all_joins = |query: post_aggregates::BoxedQuery<'a, Pg>, my_person_id: Option<PersonId>| { let is_creator_banned_from_community = exists(
// The left join below will return None in this case community_person_ban::table.filter(
let person_id_join = my_person_id.unwrap_or(PersonId(-1));
query
.inner_join(person::table)
.inner_join(community::table)
.left_join(
community_person_ban::table.on(
post_aggregates::community_id post_aggregates::community_id
.eq(community_person_ban::community_id) .eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(post_aggregates::creator_id)), .and(community_person_ban::person_id.eq(post_aggregates::creator_id)),
), ),
) );
.inner_join(post::table)
.left_join( let is_saved = |person_id| {
community_follower::table.on( exists(
post_aggregates::community_id post_saved::table.filter(
.eq(community_follower::community_id)
.and(community_follower::person_id.eq(person_id_join)),
),
)
.left_join(
community_moderator::table.on(
post::community_id
.eq(community_moderator::community_id)
.and(community_moderator::person_id.eq(person_id_join)),
),
)
.left_join(
post_saved::table.on(
post_aggregates::post_id post_aggregates::post_id
.eq(post_saved::post_id) .eq(post_saved::post_id)
.and(post_saved::person_id.eq(person_id_join)), .and(post_saved::person_id.eq(person_id)),
),
)
.left_join(
post_read::table.on(
post_aggregates::post_id
.eq(post_read::post_id)
.and(post_read::person_id.eq(person_id_join)),
),
)
.left_join(
person_block::table.on(
post_aggregates::creator_id
.eq(person_block::target_id)
.and(person_block::person_id.eq(person_id_join)),
),
)
.left_join(
post_like::table.on(
post_aggregates::post_id
.eq(post_like::post_id)
.and(post_like::person_id.eq(person_id_join)),
),
)
.left_join(
person_post_aggregates::table.on(
post_aggregates::post_id
.eq(person_post_aggregates::post_id)
.and(person_post_aggregates::person_id.eq(person_id_join)),
), ),
) )
}; };
let selection = ( let is_read = |person_id| {
exists(
post_read::table.filter(
post_aggregates::post_id
.eq(post_read::post_id)
.and(post_read::person_id.eq(person_id)),
),
)
};
let is_creator_blocked = |person_id| {
exists(
person_block::table.filter(
post_aggregates::creator_id
.eq(person_block::target_id)
.and(person_block::person_id.eq(person_id)),
),
)
};
let score = |person_id| {
post_like::table
.filter(
post_aggregates::post_id
.eq(post_like::post_id)
.and(post_like::person_id.eq(person_id)),
)
.select(post_like::score.nullable())
.single_value()
};
let all_joins = move |query: post_aggregates::BoxedQuery<'a, Pg>,
my_person_id: Option<PersonId>,
saved_only: bool| {
let is_saved_selection: Box<dyn BoxableExpression<_, Pg, SqlType = sql_types::Bool>> =
if saved_only {
Box::new(true.into_sql::<sql_types::Bool>())
} else if let Some(person_id) = my_person_id {
Box::new(is_saved(person_id))
} else {
Box::new(false.into_sql::<sql_types::Bool>())
};
let is_read_selection: Box<dyn BoxableExpression<_, Pg, SqlType = sql_types::Bool>> =
if let Some(person_id) = my_person_id {
Box::new(is_read(person_id))
} else {
Box::new(false.into_sql::<sql_types::Bool>())
};
let is_creator_blocked_selection: Box<dyn BoxableExpression<_, Pg, SqlType = sql_types::Bool>> =
if let Some(person_id) = my_person_id {
Box::new(is_creator_blocked(person_id))
} else {
Box::new(false.into_sql::<sql_types::Bool>())
};
let subscribed_type_selection: Box<
dyn BoxableExpression<_, Pg, SqlType = sql_types::Nullable<sql_types::Bool>>,
> = if let Some(person_id) = my_person_id {
Box::new(
community_follower::table
.filter(
post_aggregates::community_id
.eq(community_follower::community_id)
.and(community_follower::person_id.eq(person_id)),
)
.select(community_follower::pending.nullable())
.single_value(),
)
} else {
Box::new(None::<bool>.into_sql::<sql_types::Nullable<sql_types::Bool>>())
};
let score_selection: Box<
dyn BoxableExpression<_, Pg, SqlType = sql_types::Nullable<sql_types::SmallInt>>,
> = if let Some(person_id) = my_person_id {
Box::new(score(person_id))
} else {
Box::new(None::<i16>.into_sql::<sql_types::Nullable<sql_types::SmallInt>>())
};
let read_comments: Box<
dyn BoxableExpression<_, Pg, SqlType = sql_types::Nullable<sql_types::BigInt>>,
> = if let Some(person_id) = my_person_id {
Box::new(
person_post_aggregates::table
.filter(
post_aggregates::post_id
.eq(person_post_aggregates::post_id)
.and(person_post_aggregates::person_id.eq(person_id)),
)
.select(person_post_aggregates::read_comments.nullable())
.single_value(),
)
} else {
Box::new(None::<i64>.into_sql::<sql_types::Nullable<sql_types::BigInt>>())
};
query
.inner_join(person::table)
.inner_join(community::table)
.inner_join(post::table)
.select((
post::all_columns, post::all_columns,
person::all_columns, person::all_columns,
community::all_columns, community::all_columns,
community_person_ban::id.nullable().is_not_null(), is_creator_banned_from_community,
post_aggregates::all_columns, post_aggregates::all_columns,
CommunityFollower::select_subscribed_type(), subscribed_type_selection,
post_saved::id.nullable().is_not_null(), is_saved_selection,
post_read::id.nullable().is_not_null(), is_read_selection,
person_block::id.nullable().is_not_null(), is_creator_blocked_selection,
post_like::score.nullable(), score_selection,
coalesce( coalesce(
post_aggregates::comments.nullable() - person_post_aggregates::read_comments.nullable(), post_aggregates::comments.nullable() - read_comments,
post_aggregates::comments, post_aggregates::comments,
), ),
); ))
};
let read = let read =
move |mut conn: DbConn<'a>, move |mut conn: DbConn<'a>,
@ -140,8 +195,8 @@ fn queries<'a>() -> Queries<
.filter(post_aggregates::post_id.eq(post_id)) .filter(post_aggregates::post_id.eq(post_id))
.into_boxed(), .into_boxed(),
my_person_id, my_person_id,
) false,
.select(selection); );
// Hide deleted and removed for non-admins or mods // Hide deleted and removed for non-admins or mods
if !is_mod_or_admin { if !is_mod_or_admin {
@ -172,22 +227,11 @@ fn queries<'a>() -> Queries<
let person_id_join = person_id.unwrap_or(PersonId(-1)); let person_id_join = person_id.unwrap_or(PersonId(-1));
let local_user_id_join = local_user_id.unwrap_or(LocalUserId(-1)); let local_user_id_join = local_user_id.unwrap_or(LocalUserId(-1));
let mut query = all_joins(post_aggregates::table.into_boxed(), person_id) let mut query = all_joins(
.left_join( post_aggregates::table.into_boxed(),
community_block::table.on( person_id,
post_aggregates::community_id options.saved_only,
.eq(community_block::community_id) );
.and(community_block::person_id.eq(person_id_join)),
),
)
.left_join(
local_user_language::table.on(
post::language_id
.eq(local_user_language::language_id)
.and(local_user_language::local_user_id.eq(local_user_id_join)),
),
)
.select(selection);
let is_creator = options.creator_id == options.local_user.map(|l| l.person.id); let is_creator = options.creator_id == options.local_user.map(|l| l.person.id);
// only show deleted posts to creator // only show deleted posts to creator
@ -220,25 +264,30 @@ fn queries<'a>() -> Queries<
query = query.filter(post_aggregates::creator_id.eq(creator_id)); query = query.filter(post_aggregates::creator_id.eq(creator_id));
} }
if let Some(listing_type) = options.listing_type { if let (Some(listing_type), Some(person_id)) = (options.listing_type, person_id) {
match listing_type { let is_subscribed = exists(
ListingType::Subscribed => query = query.filter(community_follower::pending.is_not_null()), community_follower::table.filter(
ListingType::Local => { post_aggregates::community_id
query = query.filter(community::local.eq(true)).filter( .eq(community_follower::community_id)
community::hidden .and(community_follower::person_id.eq(person_id)),
.eq(false) ),
.or(community_follower::person_id.eq(person_id_join)),
); );
match listing_type {
ListingType::Subscribed => query = query.filter(is_subscribed),
ListingType::Local => {
query = query
.filter(community::local.eq(true))
.filter(community::hidden.eq(false).or(is_subscribed));
} }
ListingType::All => { ListingType::All => query = query.filter(community::hidden.eq(false).or(is_subscribed)),
query = query.filter(
community::hidden
.eq(false)
.or(community_follower::person_id.eq(person_id_join)),
)
}
ListingType::ModeratorView => { ListingType::ModeratorView => {
query = query.filter(community_moderator::person_id.is_not_null()); query = query.filter(exists(
community_moderator::table.filter(
post::community_id
.eq(community_moderator::community_id)
.and(community_moderator::person_id.eq(person_id)),
),
));
} }
} }
} }
@ -274,8 +323,8 @@ fn queries<'a>() -> Queries<
query = query.filter(person::bot_account.eq(false)); query = query.filter(person::bot_account.eq(false));
}; };
if options.saved_only { if let (true, Some(person_id)) = (options.saved_only, person_id) {
query = query.filter(post_saved::id.is_not_null()); query = query.filter(is_saved(person_id));
} }
// Only hide the read posts, if the saved_only is false. Otherwise ppl with the hide_read // Only hide the read posts, if the saved_only is false. Otherwise ppl with the hide_read
// setting wont be able to see saved posts. // setting wont be able to see saved posts.
@ -285,27 +334,42 @@ fn queries<'a>() -> Queries<
.unwrap_or(true) .unwrap_or(true)
{ {
// Do not hide read posts when it is a user profile view // Do not hide read posts when it is a user profile view
if !options.is_profile_view { if let (false, Some(person_id)) = (options.is_profile_view, person_id) {
query = query.filter(post_read::post_id.is_null()); query = query.filter(not(is_read(person_id)));
} }
} }
if let Some(person_id) = person_id {
if options.liked_only { if options.liked_only {
query = query.filter(post_like::score.eq(1)); query = query.filter(score(person_id).eq(1));
} else if options.disliked_only { } else if options.disliked_only {
query = query.filter(post_like::score.eq(-1)); query = query.filter(score(person_id).eq(-1));
} }
};
// Dont filter blocks or missing languages for moderator view type // Dont filter blocks or missing languages for moderator view type
if options.local_user.is_some() if let (Some(person_id), false) = (
&& options.listing_type.unwrap_or_default() != ListingType::ModeratorView person_id,
{ options.listing_type.unwrap_or_default() == ListingType::ModeratorView,
) {
// Filter out the rows with missing languages // Filter out the rows with missing languages
query = query.filter(local_user_language::language_id.is_not_null()); query = query.filter(exists(
local_user_language::table.filter(
post::language_id
.eq(local_user_language::language_id)
.and(local_user_language::local_user_id.eq(local_user_id_join)),
),
));
// Don't show blocked communities or persons // Don't show blocked communities or persons
query = query.filter(community_block::person_id.is_null()); query = query.filter(not(exists(
query = query.filter(person_block::person_id.is_null()); community_block::table.filter(
post_aggregates::community_id
.eq(community_block::community_id)
.and(community_block::person_id.eq(person_id_join)),
),
)));
query = query.filter(not(is_creator_blocked(person_id)));
} }
let now = diesel::dsl::now.into_sql::<Timestamptz>(); let now = diesel::dsl::now.into_sql::<Timestamptz>();

@ -1 +1 @@
Subproject commit 713ceed9c7ef84deaa222e68361e670e0763cd83 Subproject commit 1c42c579460871de7b4ea18e58dc25543b80d289