mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-12-22 19:01:32 +00:00
Filters done, working on tests.
This commit is contained in:
parent
4586947910
commit
389083418c
1 changed files with 259 additions and 146 deletions
|
@ -9,11 +9,13 @@ use crate::structs::{
|
|||
SearchCombinedViewInternal,
|
||||
};
|
||||
use diesel::{
|
||||
dsl::not,
|
||||
result::Error,
|
||||
BoolExpressionMethods,
|
||||
ExpressionMethods,
|
||||
JoinOnDsl,
|
||||
NullableExpressionMethods,
|
||||
PgTextExpressionMethods,
|
||||
QueryDsl,
|
||||
SelectableHelper,
|
||||
};
|
||||
|
@ -21,7 +23,7 @@ use diesel_async::RunQueryDsl;
|
|||
use i_love_jesus::PaginatedQueryBuilder;
|
||||
use lemmy_db_schema::{
|
||||
aliases::creator_community_actions,
|
||||
newtypes::PersonId,
|
||||
newtypes::{CommunityId, PersonId},
|
||||
schema::{
|
||||
comment,
|
||||
comment_actions,
|
||||
|
@ -43,8 +45,10 @@ use lemmy_db_schema::{
|
|||
combined::search::{search_combined_keys as key, SearchCombined},
|
||||
community::CommunityFollower,
|
||||
},
|
||||
utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool},
|
||||
utils::{actions, actions_alias, functions::coalesce, fuzzy_search, get_conn, DbPool},
|
||||
InternalToCombinedView,
|
||||
ListingType,
|
||||
SearchType,
|
||||
};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
|
@ -84,12 +88,20 @@ impl SearchCombinedPaginationCursor {
|
|||
#[derive(Clone)]
|
||||
pub struct PaginationCursorData(SearchCombined);
|
||||
|
||||
#[derive(derive_new::new)]
|
||||
#[derive(Default)]
|
||||
pub struct SearchCombinedQuery {
|
||||
pub creator_id: PersonId,
|
||||
#[new(default)]
|
||||
pub search_term: Option<String>,
|
||||
pub community_id: Option<CommunityId>,
|
||||
pub creator_id: Option<PersonId>,
|
||||
pub type_: Option<SearchType>,
|
||||
// TODO sorts need to be added
|
||||
// pub sort: Option<PostSortType>,
|
||||
pub listing_type: Option<ListingType>,
|
||||
pub title_only: Option<bool>,
|
||||
pub post_url_only: Option<bool>,
|
||||
pub liked_only: Option<bool>,
|
||||
pub disliked_only: Option<bool>,
|
||||
pub page_after: Option<PaginationCursorData>,
|
||||
#[new(default)]
|
||||
pub page_back: Option<bool>,
|
||||
}
|
||||
|
||||
|
@ -132,7 +144,7 @@ impl SearchCombinedQuery {
|
|||
// For example, the creator must be the person table joined to either:
|
||||
// - post.creator_id
|
||||
// - comment.creator_id
|
||||
let query = search_combined::table
|
||||
let mut query = search_combined::table
|
||||
// The comment
|
||||
.left_join(comment::table.on(comment_join))
|
||||
// The post
|
||||
|
@ -217,6 +229,112 @@ impl SearchCombinedQuery {
|
|||
))
|
||||
.into_boxed();
|
||||
|
||||
// The filters
|
||||
|
||||
// The search term
|
||||
if let Some(search_term) = &self.search_term {
|
||||
if self.post_url_only.unwrap_or_default() {
|
||||
query = query.filter(post::url.eq(search_term));
|
||||
} else {
|
||||
let searcher = fuzzy_search(search_term);
|
||||
|
||||
let name_or_title_filter = post::name
|
||||
.ilike(searcher.clone())
|
||||
.or(comment::content.ilike(searcher.clone()))
|
||||
.or(community::name.ilike(searcher.clone()))
|
||||
.or(community::title.ilike(searcher.clone()))
|
||||
.or(person::name.ilike(searcher.clone()))
|
||||
.or(person::display_name.ilike(searcher.clone()));
|
||||
|
||||
let body_or_description_filter = post::body
|
||||
.ilike(searcher.clone())
|
||||
.or(community::description.ilike(searcher.clone()));
|
||||
|
||||
query = if self.title_only.unwrap_or_default() {
|
||||
query.filter(name_or_title_filter)
|
||||
} else {
|
||||
query.filter(name_or_title_filter.or(body_or_description_filter))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Community id
|
||||
if let Some(community_id) = self.community_id {
|
||||
query = query.filter(community::id.eq(community_id));
|
||||
}
|
||||
|
||||
// Creator id
|
||||
if let Some(creator_id) = self.creator_id {
|
||||
query = query.filter(item_creator.eq(creator_id));
|
||||
}
|
||||
|
||||
// Liked / disliked filter
|
||||
if let Some(my_id) = my_person_id {
|
||||
let not_creator_filter = item_creator.ne(my_id);
|
||||
// TODO do I need not null checks for these?
|
||||
let liked_disliked_filter = |score: i16| {
|
||||
search_combined::post_id
|
||||
.is_not_null()
|
||||
.and(post_actions::like_score.eq(score))
|
||||
.or(
|
||||
search_combined::comment_id
|
||||
.is_not_null()
|
||||
.and(comment_actions::like_score.eq(score)),
|
||||
)
|
||||
};
|
||||
|
||||
if self.liked_only.unwrap_or_default() {
|
||||
query = query
|
||||
.filter(not_creator_filter)
|
||||
.filter(liked_disliked_filter(1));
|
||||
} else if self.disliked_only.unwrap_or_default() {
|
||||
query = query
|
||||
.filter(not_creator_filter)
|
||||
.filter(liked_disliked_filter(-1));
|
||||
}
|
||||
};
|
||||
|
||||
// Type
|
||||
if let Some(type_) = self.type_ {
|
||||
query = match type_ {
|
||||
SearchType::All => query,
|
||||
SearchType::Posts => query.filter(search_combined::post_id.is_not_null()),
|
||||
SearchType::Comments => query.filter(search_combined::comment_id.is_not_null()),
|
||||
SearchType::Communities => query.filter(search_combined::community_id.is_not_null()),
|
||||
SearchType::Users => query.filter(search_combined::person_id.is_not_null()),
|
||||
}
|
||||
}
|
||||
|
||||
// Listing type
|
||||
// TODO need null checks for this one?
|
||||
let is_subscribed = community_actions::followed.is_not_null();
|
||||
match self.listing_type.unwrap_or_default() {
|
||||
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 => query = query.filter(community::hidden.eq(false).or(is_subscribed)),
|
||||
ListingType::ModeratorView => {
|
||||
query = query.filter(community_actions::became_moderator.is_not_null());
|
||||
}
|
||||
}
|
||||
|
||||
// Deleted / removed filters
|
||||
// TODO need null checks for this?
|
||||
query = query.filter(not(
|
||||
comment::removed
|
||||
.or(comment::deleted)
|
||||
.or(post::removed)
|
||||
.or(post::deleted)
|
||||
.or(community::removed)
|
||||
.or(community::deleted)
|
||||
.or(community::removed)
|
||||
.or(community::deleted)
|
||||
.or(person::deleted),
|
||||
));
|
||||
|
||||
let mut query = PaginatedQueryBuilder::new(query);
|
||||
|
||||
let page_after = self.page_after.map(|c| c.0);
|
||||
|
@ -311,164 +429,159 @@ impl InternalToCombinedView for SearchCombinedViewInternal {
|
|||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// #[expect(clippy::indexing_slicing)]
|
||||
// mod tests {
|
||||
#[cfg(test)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
// use crate::{
|
||||
// combined::search_combined_view::SearchCombinedQuery,
|
||||
// structs::SearchCombinedView,
|
||||
// };
|
||||
// use lemmy_db_schema::{
|
||||
// source::{
|
||||
// comment::{Comment, CommentInsertForm},
|
||||
// community::{Community, CommunityInsertForm},
|
||||
// instance::Instance,
|
||||
// person::{Person, PersonInsertForm},
|
||||
// post::{Post, PostInsertForm},
|
||||
// },
|
||||
// traits::Crud,
|
||||
// utils::{build_db_pool_for_tests, DbPool},
|
||||
// };
|
||||
// use lemmy_utils::error::LemmyResult;
|
||||
// use pretty_assertions::assert_eq;
|
||||
// use serial_test::serial;
|
||||
use crate::{combined::search_combined_view::SearchCombinedQuery, structs::SearchCombinedView};
|
||||
use lemmy_db_schema::{
|
||||
assert_length,
|
||||
source::{
|
||||
comment::{Comment, CommentInsertForm},
|
||||
community::{Community, CommunityInsertForm},
|
||||
instance::Instance,
|
||||
person::{Person, PersonInsertForm},
|
||||
post::{Post, PostInsertForm},
|
||||
},
|
||||
traits::Crud,
|
||||
utils::{build_db_pool_for_tests, DbPool},
|
||||
};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serial_test::serial;
|
||||
|
||||
// struct Data {
|
||||
// instance: Instance,
|
||||
// timmy: Person,
|
||||
// sara: Person,
|
||||
// timmy_post: Post,
|
||||
// timmy_post_2: Post,
|
||||
// sara_post: Post,
|
||||
// timmy_comment: Comment,
|
||||
// sara_comment: Comment,
|
||||
// sara_comment_2: Comment,
|
||||
// }
|
||||
struct Data {
|
||||
instance: Instance,
|
||||
timmy: Person,
|
||||
sara: Person,
|
||||
community: Community,
|
||||
community_2: Community,
|
||||
timmy_post: Post,
|
||||
timmy_post_2: Post,
|
||||
sara_post: Post,
|
||||
timmy_comment: Comment,
|
||||
sara_comment: Comment,
|
||||
sara_comment_2: Comment,
|
||||
}
|
||||
|
||||
// async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
|
||||
// let instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||
async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
|
||||
let instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||
|
||||
// let timmy_form = PersonInsertForm::test_form(instance.id, "timmy_pcv");
|
||||
// let timmy = Person::create(pool, &timmy_form).await?;
|
||||
let timmy_form = PersonInsertForm::test_form(instance.id, "timmy_pcv");
|
||||
let timmy = Person::create(pool, &timmy_form).await?;
|
||||
|
||||
// let sara_form = PersonInsertForm::test_form(instance.id, "sara_pcv");
|
||||
// let sara = Person::create(pool, &sara_form).await?;
|
||||
let sara_form = PersonInsertForm::test_form(instance.id, "sara_pcv");
|
||||
let sara = Person::create(pool, &sara_form).await?;
|
||||
|
||||
// let community_form = CommunityInsertForm::new(
|
||||
// instance.id,
|
||||
// "test community pcv".to_string(),
|
||||
// "nada".to_owned(),
|
||||
// "pubkey".to_string(),
|
||||
// );
|
||||
// let community = Community::create(pool, &community_form).await?;
|
||||
let community_form = CommunityInsertForm::new(
|
||||
instance.id,
|
||||
"asklemmy".to_string(),
|
||||
"Ask Lemmy".to_owned(),
|
||||
"pubkey".to_string(),
|
||||
);
|
||||
let community = Community::create(pool, &community_form).await?;
|
||||
|
||||
// let timmy_post_form = PostInsertForm::new("timmy post prv".into(), timmy.id, community.id);
|
||||
// let timmy_post = Post::create(pool, &timmy_post_form).await?;
|
||||
let community_form_2 = CommunityInsertForm::new(
|
||||
instance.id,
|
||||
"startrek_ds9".to_string(),
|
||||
"Star Trek - Deep Space Nine".to_owned(),
|
||||
"pubkey".to_string(),
|
||||
);
|
||||
let community_2 = Community::create(pool, &community_form_2).await?;
|
||||
|
||||
// let timmy_post_form_2 = PostInsertForm::new("timmy post prv 2".into(), timmy.id,
|
||||
// community.id); let timmy_post_2 = Post::create(pool, &timmy_post_form_2).await?;
|
||||
let timmy_post_form = PostInsertForm::new("timmy post prv".into(), timmy.id, community.id);
|
||||
let timmy_post = Post::create(pool, &timmy_post_form).await?;
|
||||
|
||||
// let sara_post_form = PostInsertForm::new("sara post prv".into(), sara.id, community.id);
|
||||
// let sara_post = Post::create(pool, &sara_post_form).await?;
|
||||
let timmy_post_form_2 = PostInsertForm::new("timmy post prv 2".into(), timmy.id, community.id);
|
||||
let timmy_post_2 = Post::create(pool, &timmy_post_form_2).await?;
|
||||
|
||||
// let timmy_comment_form =
|
||||
// CommentInsertForm::new(timmy.id, timmy_post.id, "timmy comment prv".into());
|
||||
// let timmy_comment = Comment::create(pool, &timmy_comment_form, None).await?;
|
||||
let sara_post_form = PostInsertForm::new("sara post prv".into(), sara.id, community.id);
|
||||
let sara_post = Post::create(pool, &sara_post_form).await?;
|
||||
|
||||
// let sara_comment_form =
|
||||
// CommentInsertForm::new(sara.id, timmy_post.id, "sara comment prv".into());
|
||||
// let sara_comment = Comment::create(pool, &sara_comment_form, None).await?;
|
||||
let timmy_comment_form =
|
||||
CommentInsertForm::new(timmy.id, timmy_post.id, "timmy comment prv".into());
|
||||
let timmy_comment = Comment::create(pool, &timmy_comment_form, None).await?;
|
||||
|
||||
// let sara_comment_form_2 =
|
||||
// CommentInsertForm::new(sara.id, timmy_post_2.id, "sara comment prv 2".into());
|
||||
// let sara_comment_2 = Comment::create(pool, &sara_comment_form_2, None).await?;
|
||||
let sara_comment_form =
|
||||
CommentInsertForm::new(sara.id, timmy_post.id, "sara comment prv".into());
|
||||
let sara_comment = Comment::create(pool, &sara_comment_form, None).await?;
|
||||
|
||||
// Ok(Data {
|
||||
// instance,
|
||||
// timmy,
|
||||
// sara,
|
||||
// timmy_post,
|
||||
// timmy_post_2,
|
||||
// sara_post,
|
||||
// timmy_comment,
|
||||
// sara_comment,
|
||||
// sara_comment_2,
|
||||
// })
|
||||
// }
|
||||
let sara_comment_form_2 =
|
||||
CommentInsertForm::new(sara.id, timmy_post_2.id, "sara comment prv 2".into());
|
||||
let sara_comment_2 = Comment::create(pool, &sara_comment_form_2, None).await?;
|
||||
|
||||
// async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
|
||||
// Instance::delete(pool, data.instance.id).await?;
|
||||
Ok(Data {
|
||||
instance,
|
||||
timmy,
|
||||
sara,
|
||||
community,
|
||||
community_2,
|
||||
timmy_post,
|
||||
timmy_post_2,
|
||||
sara_post,
|
||||
timmy_comment,
|
||||
sara_comment,
|
||||
sara_comment_2,
|
||||
})
|
||||
}
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
|
||||
Instance::delete(pool, data.instance.id).await?;
|
||||
|
||||
// #[tokio::test]
|
||||
// #[serial]
|
||||
// async fn test_combined() -> LemmyResult<()> {
|
||||
// let pool = &build_db_pool_for_tests();
|
||||
// let pool = &mut pool.into();
|
||||
// let data = init_data(pool).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// // Do a batch read of timmy
|
||||
// let timmy_content = SearchCombinedQuery::new(data.timmy.id)
|
||||
// .list(pool, &None)
|
||||
// .await?;
|
||||
// assert_eq!(3, timmy_content.len());
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn community_search() -> LemmyResult<()> {
|
||||
let pool = &build_db_pool_for_tests();
|
||||
let pool = &mut pool.into();
|
||||
let data = init_data(pool).await?;
|
||||
|
||||
// // Make sure the types are correct
|
||||
// if let SearchCombinedView::Comment(v) = &timmy_content[0] {
|
||||
// assert_eq!(data.timmy_comment.id, v.comment.id);
|
||||
// assert_eq!(data.timmy.id, v.creator.id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
// if let SearchCombinedView::Post(v) = &timmy_content[1] {
|
||||
// assert_eq!(data.timmy_post_2.id, v.post.id);
|
||||
// assert_eq!(data.timmy.id, v.post.creator_id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
// if let SearchCombinedView::Post(v) = &timmy_content[2] {
|
||||
// assert_eq!(data.timmy_post.id, v.post.id);
|
||||
// assert_eq!(data.timmy.id, v.post.creator_id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
// Community search
|
||||
let community_search = SearchCombinedQuery::default().list(pool, &None).await?;
|
||||
assert_length!(2, community_search);
|
||||
|
||||
// // Do a batch read of sara
|
||||
// let sara_content = SearchCombinedQuery::new(data.sara.id)
|
||||
// .list(pool, &None)
|
||||
// .await?;
|
||||
// assert_eq!(3, sara_content.len());
|
||||
// Make sure the types are correct
|
||||
if let SearchCombinedView::Community(v) = &community_search[0] {
|
||||
assert_eq!(data.community_2.id, v.community.id);
|
||||
} else {
|
||||
panic!("wrong type");
|
||||
}
|
||||
|
||||
// // Make sure the report types are correct
|
||||
// if let SearchCombinedView::Comment(v) = &sara_content[0] {
|
||||
// assert_eq!(data.sara_comment_2.id, v.comment.id);
|
||||
// assert_eq!(data.sara.id, v.creator.id);
|
||||
// // This one was to timmy_post_2
|
||||
// assert_eq!(data.timmy_post_2.id, v.post.id);
|
||||
// assert_eq!(data.timmy.id, v.post.creator_id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
// if let SearchCombinedView::Comment(v) = &sara_content[1] {
|
||||
// assert_eq!(data.sara_comment.id, v.comment.id);
|
||||
// assert_eq!(data.sara.id, v.creator.id);
|
||||
// assert_eq!(data.timmy_post.id, v.post.id);
|
||||
// assert_eq!(data.timmy.id, v.post.creator_id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
// if let SearchCombinedView::Post(v) = &sara_content[2] {
|
||||
// assert_eq!(data.sara_post.id, v.post.id);
|
||||
// assert_eq!(data.sara.id, v.post.creator_id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
if let SearchCombinedView::Community(v) = &community_search[1] {
|
||||
assert_eq!(data.community.id, v.community.id);
|
||||
} else {
|
||||
panic!("wrong type");
|
||||
}
|
||||
|
||||
// cleanup(data, pool).await?;
|
||||
// Filtered by id
|
||||
let community_search_by_id = SearchCombinedQuery {
|
||||
community_id: Some(data.community.id),
|
||||
..Default::default()
|
||||
}
|
||||
.list(pool, &None)
|
||||
.await?;
|
||||
assert_length!(1, community_search_by_id);
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
// Using a term
|
||||
let community_search_by_name = SearchCombinedQuery {
|
||||
search_term: Some("Ask".into()),
|
||||
..Default::default()
|
||||
}
|
||||
.list(pool, &None)
|
||||
.await?;
|
||||
|
||||
assert_length!(1, community_search_by_name);
|
||||
if let SearchCombinedView::Community(v) = &community_search_by_name[0] {
|
||||
// The asklemmy community
|
||||
assert_eq!(data.community.id, v.community.id);
|
||||
} else {
|
||||
panic!("wrong type");
|
||||
}
|
||||
|
||||
cleanup(data, pool).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue