improve admin and mod check to not do seq scans and return unnecessary data (#3483)

* improve admin and mod check

* fix clippy

* move admin index to existing code

* Revert "move admin index to existing code"

This reverts commit d0c58d5f4021e1775d0c1d30d8df6c7df87557c4.

* third attempt at the migration

* fix formatting

* rebuild

---------

Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
This commit is contained in:
phiresky 2023-07-06 14:44:26 +02:00 committed by GitHub
parent 00f9f79a44
commit 922ee6a230
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 39 additions and 21 deletions

View file

@ -1,5 +1,5 @@
use crate::structs::CommunityModeratorView; use crate::structs::CommunityModeratorView;
use diesel::{result::Error, ExpressionMethods, QueryDsl}; use diesel::{dsl::exists, result::Error, select, ExpressionMethods, QueryDsl};
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::{CommunityId, PersonId}, newtypes::{CommunityId, PersonId},
@ -12,6 +12,25 @@ use lemmy_db_schema::{
type CommunityModeratorViewTuple = (Community, Person); type CommunityModeratorViewTuple = (Community, Person);
impl CommunityModeratorView { impl CommunityModeratorView {
pub async fn is_community_moderator(
pool: &DbPool,
find_community_id: CommunityId,
find_person_id: PersonId,
) -> Result<bool, Error> {
use lemmy_db_schema::schema::community_moderator::dsl::{
community_id,
community_moderator,
person_id,
};
let conn = &mut get_conn(pool).await?;
select(exists(
community_moderator
.filter(community_id.eq(find_community_id))
.filter(person_id.eq(find_person_id)),
))
.get_result::<bool>(conn)
.await
}
pub async fn for_community(pool: &DbPool, community_id: CommunityId) -> Result<Vec<Self>, Error> { pub async fn for_community(pool: &DbPool, community_id: CommunityId) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
let res = community_moderator::table let res = community_moderator::table

View file

@ -90,29 +90,13 @@ impl CommunityView {
person_id: PersonId, person_id: PersonId,
community_id: CommunityId, community_id: CommunityId,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
let is_mod = CommunityModeratorView::for_community(pool, community_id) let is_mod =
.await CommunityModeratorView::is_community_moderator(pool, community_id, person_id).await?;
.map(|v| {
v.into_iter()
.map(|m| m.moderator.id)
.collect::<Vec<PersonId>>()
})
.unwrap_or_default()
.contains(&person_id);
if is_mod { if is_mod {
return Ok(true); return Ok(true);
} }
let is_admin = PersonView::admins(pool) PersonView::is_admin(pool, person_id).await
.await
.map(|v| {
v.into_iter()
.map(|a| a.person.id)
.collect::<Vec<PersonId>>()
})
.unwrap_or_default()
.contains(&person_id);
Ok(is_admin)
} }
} }

View file

@ -11,6 +11,7 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::PersonAggregates, aggregates::structs::PersonAggregates,
newtypes::PersonId, newtypes::PersonId,
schema,
schema::{person, person_aggregates}, schema::{person, person_aggregates},
source::person::Person, source::person::Person,
traits::JoinView, traits::JoinView,
@ -34,6 +35,16 @@ impl PersonView {
Ok(Self::from_tuple(res)) Ok(Self::from_tuple(res))
} }
pub async fn is_admin(pool: &DbPool, person_id: PersonId) -> Result<bool, Error> {
use schema::person::dsl::{admin, id, person};
let conn = &mut get_conn(pool).await?;
let is_admin = person
.filter(id.eq(person_id))
.select(admin)
.first::<bool>(conn)
.await?;
Ok(is_admin)
}
pub async fn admins(pool: &DbPool) -> Result<Vec<Self>, Error> { pub async fn admins(pool: &DbPool) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
let admins = person::table let admins = person::table

View file

@ -1,5 +1,5 @@
-- Create an admin person index -- Create an admin person index
create index idx_person_admin on person (admin); create index if not exists idx_person_admin on person (admin);
-- Compound indexes, using featured_, then the other sorts, proved to be much faster -- Compound indexes, using featured_, then the other sorts, proved to be much faster
-- Drop the old indexes -- Drop the old indexes

View file

@ -0,0 +1,2 @@
drop index idx_person_admin;
create index idx_person_admin on person(admin);

View file

@ -0,0 +1,2 @@
drop index if exists idx_person_admin;
create index idx_person_admin on person(admin) where admin; -- allow quickly finding all admins (PersonView::admins)