Add queries function

pull/3663/head
dull b 2023-07-19 05:54:30 +00:00
parent 47000ff9a8
commit 2aec4d68a8
3 changed files with 132 additions and 140 deletions

1
Cargo.lock generated
View File

@ -2762,6 +2762,7 @@ dependencies = [
"diesel", "diesel",
"diesel-async", "diesel-async",
"diesel_ltree", "diesel_ltree",
"futures",
"lemmy_db_schema", "lemmy_db_schema",
"serde", "serde",
"serde_with", "serde_with",

View File

@ -30,6 +30,7 @@ serde = { workspace = true }
serde_with = { workspace = true } serde_with = { workspace = true }
tracing = { workspace = true, optional = true } tracing = { workspace = true, optional = true }
ts-rs = { workspace = true, optional = true } ts-rs = { workspace = true, optional = true }
futures = { workspace = true }
[dev-dependencies] [dev-dependencies]
serial_test = { workspace = true } serial_test = { workspace = true }

View File

@ -1,25 +1,17 @@
use crate::structs::CommentReportView; use crate::structs::CommentReportView;
use diesel::{ use diesel::{
dsl,
dsl::now, dsl::now,
helper_types::AliasedFields,
pg::Pg, pg::Pg,
query_builder::{AsQuery, Query, QueryFragment, QueryId, SelectQuery},
query_dsl::methods,
result::Error, result::Error,
sql_types, sql_types,
sql_types::Nullable,
BoolExpressionMethods, BoolExpressionMethods,
BoxableExpression,
Expression,
ExpressionMethods, ExpressionMethods,
JoinOnDsl, JoinOnDsl,
JoinTo,
NullableExpressionMethods, NullableExpressionMethods,
QueryDsl, QueryDsl,
Table,
}; };
use diesel_async::{methods::LoadQuery, RunQueryDsl}; use diesel_async::RunQueryDsl;
use futures::future::BoxFuture;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::CommentAggregates, aggregates::structs::CommentAggregates,
newtypes::{CommentReportId, CommunityId, PersonId}, newtypes::{CommentReportId, CommunityId, PersonId},
@ -44,101 +36,138 @@ use lemmy_db_schema::{
traits::JoinView, traits::JoinView,
utils::{get_conn, limit_and_offset, DbConn, DbPool}, utils::{get_conn, limit_and_offset, DbConn, DbPool},
}; };
use std::{future::Future, pin::Pin};
diesel::alias!(person as person_alias_1: PersonAlias1, person as person_alias_2:PersonAlias2); diesel::alias!(person as person_alias_1: PersonAlias1, person as person_alias_2:PersonAlias2);
type Selection = ( fn queries<'a>() -> (
<comment_report::table as Table>::AllColumns, impl Fn(
<comment::table as Table>::AllColumns, DbConn<'a>,
<post::table as Table>::AllColumns, CommentReportId,
<community::table as Table>::AllColumns, PersonId,
<person::table as Table>::AllColumns, ) -> BoxFuture<'a, Result<<CommentReportView as JoinView>::JoinTuple, Error>>,
AliasedFields<PersonAlias1, <person::table as Table>::AllColumns>, impl Fn(
<comment_aggregates::table as Table>::AllColumns, DbConn<'a>,
dsl::Nullable<<community_person_ban::table as Table>::AllColumns>, CommentReportQuery,
dsl::Nullable<comment_like::score>, &'a Person,
dsl::Nullable<AliasedFields<PersonAlias2, <person::table as Table>::AllColumns>>, ) -> BoxFuture<'a, Result<Vec<<CommentReportView as JoinView>::JoinTuple>, Error>>,
); ) {
let full_query = move |query: comment_report::BoxedQuery<'static, Pg>,
my_person_id: PersonId,
include_expired: bool| {
query
.inner_join(comment::table.on(comment_report::comment_id.eq(comment::id)))
.inner_join(post::table.on(comment::post_id.eq(post::id)))
.inner_join(community::table.on(post::community_id.eq(community::id)))
.inner_join(person::table.on(comment_report::creator_id.eq(person::id)))
.inner_join(person_alias_1.on(comment::creator_id.eq(person_alias_1.field(person::id))))
.inner_join(
comment_aggregates::table.on(comment_report::comment_id.eq(comment_aggregates::comment_id)),
)
.left_join(
community_person_ban::table.on(
community::id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(comment::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now))
// TODO: avoid evaluation of expiration condition if include_expired is true
.or::<_, sql_types::Nullable<sql_types::Bool>>(include_expired),
),
),
)
.left_join(
comment_like::table.on(
comment::id
.eq(comment_like::comment_id)
.and(comment_like::person_id.eq(my_person_id)),
),
)
.left_join(
person_alias_2
.on(comment_report::resolver_id.eq(person_alias_2.field(person::id).nullable())),
)
.select((
comment_report::all_columns,
comment::all_columns,
post::all_columns,
community::all_columns,
person::all_columns,
person_alias_1.fields(person::all_columns),
comment_aggregates::all_columns,
community_person_ban::all_columns.nullable(),
comment_like::score.nullable(),
person_alias_2.fields(person::all_columns).nullable(),
))
};
let read = move |mut conn: DbConn<'a>, report_id: CommentReportId, my_person_id: PersonId| {
let fut = async move {
let res = full_query(
comment_report::table.find(report_id).into_boxed(),
my_person_id,
true,
)
.first::<<CommentReportView as JoinView>::JoinTuple>(&mut conn)
.await?;
Ok::<<CommentReportView as JoinView>::JoinTuple, Error>(res)
};
let b: Pin<
Box<
dyn Future<Output = Result<<CommentReportView as JoinView>::JoinTuple, Error>> + Send + '_,
>,
> = Box::pin(fut);
b
};
let list = move |mut conn: DbConn<'a>, options: CommentReportQuery, my_person: &'a Person| {
let fut = async move {
let mut query = full_query(comment_report::table.into_boxed(), my_person.id, false);
/*trait BoxedFilter<T>:methods::FilterDsl<T,Output=Self> {} if let Some(community_id) = options.community_id {
query = query.filter(post::community_id.eq(community_id));
}
impl<T:methods::FilterDsl if options.unresolved_only.unwrap_or(false) {
query = query.filter(comment_report::resolved.eq(false));
}
trait BoxedJoin: 'static + methods::LimitDsl<Output = Self> + LoadQuery + Send + AsQuery<SqlType = <Selection as Expression>::SqlType>+FilterDsl<dsl::Eq<post::community_id,CommunityId>,Output=Self> where <Self as AsQuery>::Query: QueryFragment<Pg>+QueryId+Send+'static {} let (limit, offset) = limit_and_offset(options.page, options.limit)?;
impl<T: 'static + methods::LimitDsl<Output = T> + LoadQuery + Send + AsQuery<SqlType = <Selection as Expression>::SqlType>> BoxedJoin for T where <T as AsQuery>::Query: QueryFragment<Pg>+QueryId+Send+'static {}*/ query = query
.order_by(comment_report::published.desc())
.limit(limit)
.offset(offset);
fn full_query<'a>( // If its not an admin, get only the ones you mod
mut query: comment_report::BoxedQuery<'a, Pg>, let res = if !my_person.admin {
//report_id: Option<CommentReportId>, query
my_person_id: PersonId, .inner_join(
include_expired: bool, community_moderator::table.on(
) -> impl 'a + SelectQuery<SqlType = <Selection as Expression>::SqlType> community_moderator::community_id
/*comment_report::BoxedQuery< .eq(post::community_id)
'_, .and(community_moderator::person_id.eq(my_person.id)),
Pg, ),
<Selection as Expression>::SqlType, )
/*( .load::<<CommentReportView as JoinView>::JoinTuple>(&mut conn)
comment_report::SqlType, .await?
comment::SqlType, } else {
post::SqlType, query
community::SqlType, .load::<<CommentReportView as JoinView>::JoinTuple>(&mut conn)
person::SqlType, .await?
AliasedFields<PersonAlias1, <person::table as Table>::AllColumns>, };
comment_aggregates::SqlType, Ok::<Vec<<CommentReportView as JoinView>::JoinTuple>, Error>(res)
Nullable<community_person_ban::SqlType>, };
Nullable<<comment_like::score as Expression>::SqlType>, let b: Pin<
Nullable<AliasedFields<PersonAlias2, <person::table as Table>::AllColumns>>, Box<
)*/ dyn Future<Output = Result<Vec<<CommentReportView as JoinView>::JoinTuple>, Error>>
>*/ { + Send
//if let Some(report_id) = report_id {query = query.find(report_id);} + '_,
query >,
.inner_join(comment::table.on(comment_report::comment_id.eq(comment::id))) > = Box::pin(fut);
.inner_join(post::table.on(comment::post_id.eq(post::id))) b
.inner_join(community::table.on(post::community_id.eq(community::id))) };
.inner_join(person::table.on(comment_report::creator_id.eq(person::id))) (read, list)
.inner_join(person_alias_1.on(comment::creator_id.eq(person_alias_1.field(person::id))))
.inner_join(
comment_aggregates::table.on(comment_report::comment_id.eq(comment_aggregates::comment_id)),
)
.left_join(
community_person_ban::table.on(
community::id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(comment::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now))
// TODO: avoid evaluation of this condition if include_expired is true
.or(!include_expired),
),
),
)
.left_join(
comment_like::table.on(
comment::id
.eq(comment_like::comment_id)
.and(comment_like::person_id.eq(my_person_id)),
),
)
.left_join(
person_alias_2
.on(comment_report::resolver_id.eq(person_alias_2.field(person::id).nullable())),
)
.select::<Selection>((
comment_report::all_columns,
comment::all_columns,
post::all_columns,
community::all_columns,
person::all_columns,
person_alias_1.fields(person::all_columns),
comment_aggregates::all_columns,
community_person_ban::all_columns.nullable(),
comment_like::score.nullable(),
person_alias_2.fields(person::all_columns).nullable(),
))
//.into_boxed()
} }
impl CommentReportView { impl CommentReportView {
@ -150,15 +179,9 @@ impl CommentReportView {
report_id: CommentReportId, report_id: CommentReportId,
my_person_id: PersonId, my_person_id: PersonId,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?; let conn = get_conn(pool).await?;
let res = full_query( let res = (queries().0)(conn, report_id, my_person_id).await?;
comment_report::table.find(report_id).into_boxed(),
my_person_id,
true,
)
.first::<<CommentReportView as JoinView>::JoinTuple>(conn)
.await?;
Ok(Self::from_tuple(res)) Ok(Self::from_tuple(res))
} }
@ -220,42 +243,9 @@ impl CommentReportQuery {
pool: &mut DbPool<'_>, pool: &mut DbPool<'_>,
my_person: &Person, my_person: &Person,
) -> Result<Vec<CommentReportView>, Error> { ) -> Result<Vec<CommentReportView>, Error> {
let conn = &mut get_conn(pool).await?; let conn = get_conn(pool).await?;
let mut query = full_query(comment_report::table.into_boxed(), my_person.id, false); let res = (queries().1)(conn, self, my_person).await?;
if let Some(community_id) = self.community_id {
query = query.filter(post::community_id.eq(community_id));
}
if self.unresolved_only.unwrap_or(false) {
query = query.filter(comment_report::resolved.eq(false));
}
let (limit, offset) = limit_and_offset(self.page, self.limit)?;
query = query
.order_by(comment_report::published.desc())
.limit(limit)
.offset(offset);
// If its not an admin, get only the ones you mod
let res = if !my_person.admin {
query
.inner_join(
community_moderator::table.on(
community_moderator::community_id
.eq(post::community_id)
.and(community_moderator::person_id.eq(my_person.id)),
),
)
.load::<<CommentReportView as JoinView>::JoinTuple>(conn)
.await?
} else {
query
.load::<<CommentReportView as JoinView>::JoinTuple>(conn)
.await?
};
Ok(res.into_iter().map(CommentReportView::from_tuple).collect()) Ok(res.into_iter().map(CommentReportView::from_tuple).collect())
} }