mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-02-02 23:31:41 +00:00
Adding search_combined.score column, and DB triggers.
This commit is contained in:
parent
7e6ca820fc
commit
25920ad8b4
12 changed files with 238 additions and 490 deletions
|
@ -27,6 +27,7 @@ use lemmy_db_schema::{
|
||||||
PostListingMode,
|
PostListingMode,
|
||||||
PostSortType,
|
PostSortType,
|
||||||
RegistrationMode,
|
RegistrationMode,
|
||||||
|
SearchSortType,
|
||||||
SearchType,
|
SearchType,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{
|
use lemmy_db_views::structs::{
|
||||||
|
@ -66,8 +67,7 @@ pub struct Search {
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub type_: Option<SearchType>,
|
pub type_: Option<SearchType>,
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
// TODO
|
pub sort: Option<SearchSortType>,
|
||||||
pub sort: Option<PostSortType>,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub listing_type: Option<ListingType>,
|
pub listing_type: Option<ListingType>,
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
|
|
@ -48,7 +48,7 @@ pub async fn search(
|
||||||
community_id,
|
community_id,
|
||||||
creator_id: data.creator_id,
|
creator_id: data.creator_id,
|
||||||
type_: data.type_,
|
type_: data.type_,
|
||||||
// TODO add sorts
|
sort: data.sort,
|
||||||
listing_type: data.listing_type,
|
listing_type: data.listing_type,
|
||||||
title_only: data.title_only,
|
title_only: data.title_only,
|
||||||
post_url_only: data.post_url_only,
|
post_url_only: data.post_url_only,
|
||||||
|
|
|
@ -922,3 +922,93 @@ CALL r.create_search_combined_trigger ('community');
|
||||||
|
|
||||||
CALL r.create_search_combined_trigger ('person');
|
CALL r.create_search_combined_trigger ('person');
|
||||||
|
|
||||||
|
-- You also need to triggers to update the `score` column.
|
||||||
|
-- post | post_aggregates::score
|
||||||
|
-- comment | comment_aggregates::score
|
||||||
|
-- community | community_aggregates::users_active_monthly
|
||||||
|
-- person | person_aggregates::post_score
|
||||||
|
--
|
||||||
|
-- Post score
|
||||||
|
CREATE FUNCTION r.search_combined_post_score_update ()
|
||||||
|
RETURNS TRIGGER
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
UPDATE
|
||||||
|
search_combined
|
||||||
|
SET
|
||||||
|
score = NEW.score
|
||||||
|
WHERE
|
||||||
|
post_id = NEW.post_id;
|
||||||
|
RETURN NULL;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE TRIGGER search_combined_post_score
|
||||||
|
AFTER UPDATE OF score ON post_aggregates
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION r.search_combined_post_score_update ();
|
||||||
|
|
||||||
|
-- Comment score
|
||||||
|
CREATE FUNCTION r.search_combined_comment_score_update ()
|
||||||
|
RETURNS TRIGGER
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
UPDATE
|
||||||
|
search_combined
|
||||||
|
SET
|
||||||
|
score = NEW.score
|
||||||
|
WHERE
|
||||||
|
comment_id = NEW.comment_id;
|
||||||
|
RETURN NULL;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE TRIGGER search_combined_comment_score
|
||||||
|
AFTER UPDATE OF score ON comment_aggregates
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION r.search_combined_comment_score_update ();
|
||||||
|
|
||||||
|
-- Person score
|
||||||
|
CREATE FUNCTION r.search_combined_person_score_update ()
|
||||||
|
RETURNS TRIGGER
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
UPDATE
|
||||||
|
search_combined
|
||||||
|
SET
|
||||||
|
score = NEW.post_score
|
||||||
|
WHERE
|
||||||
|
person_id = NEW.person_id;
|
||||||
|
RETURN NULL;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE TRIGGER search_combined_person_score
|
||||||
|
AFTER UPDATE OF post_score ON person_aggregates
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION r.search_combined_person_score_update ();
|
||||||
|
|
||||||
|
-- Community score
|
||||||
|
CREATE FUNCTION r.search_combined_community_score_update ()
|
||||||
|
RETURNS TRIGGER
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
UPDATE
|
||||||
|
search_combined
|
||||||
|
SET
|
||||||
|
score = NEW.users_active_month
|
||||||
|
WHERE
|
||||||
|
community_id = NEW.community_id;
|
||||||
|
RETURN NULL;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE TRIGGER search_combined_community_score
|
||||||
|
AFTER UPDATE OF users_active_month ON community_aggregates
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION r.search_combined_community_score_update ();
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,19 @@ pub enum CommentSortType {
|
||||||
Controversial,
|
Controversial,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
|
||||||
|
)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
/// The search sort types.
|
||||||
|
pub enum SearchSortType {
|
||||||
|
#[default]
|
||||||
|
New,
|
||||||
|
Top,
|
||||||
|
Old,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
|
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
|
||||||
)]
|
)]
|
||||||
|
@ -166,11 +179,14 @@ pub enum PostListingMode {
|
||||||
SmallCard,
|
SmallCard,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(
|
||||||
|
EnumString, Display, Debug, Serialize, Deserialize, Default, Clone, Copy, PartialEq, Eq, Hash,
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", derive(TS))]
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// The type of content returned from a search.
|
/// The type of content returned from a search.
|
||||||
pub enum SearchType {
|
pub enum SearchType {
|
||||||
|
#[default]
|
||||||
All,
|
All,
|
||||||
Comments,
|
Comments,
|
||||||
Posts,
|
Posts,
|
||||||
|
|
|
@ -999,6 +999,7 @@ diesel::table! {
|
||||||
search_combined (id) {
|
search_combined (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
score -> Int8,
|
||||||
post_id -> Nullable<Int4>,
|
post_id -> Nullable<Int4>,
|
||||||
comment_id -> Nullable<Int4>,
|
comment_id -> Nullable<Int4>,
|
||||||
community_id -> Nullable<Int4>,
|
community_id -> Nullable<Int4>,
|
||||||
|
|
|
@ -20,6 +20,7 @@ use serde_with::skip_serializing_none;
|
||||||
pub struct SearchCombined {
|
pub struct SearchCombined {
|
||||||
pub id: SearchCombinedId,
|
pub id: SearchCombinedId,
|
||||||
pub published: DateTime<Utc>,
|
pub published: DateTime<Utc>,
|
||||||
|
pub score: i64,
|
||||||
pub post_id: Option<PostId>,
|
pub post_id: Option<PostId>,
|
||||||
pub comment_id: Option<CommentId>,
|
pub comment_id: Option<CommentId>,
|
||||||
pub community_id: Option<CommunityId>,
|
pub community_id: Option<CommunityId>,
|
||||||
|
|
|
@ -47,12 +47,22 @@ use lemmy_db_schema::{
|
||||||
combined::search::{search_combined_keys as key, SearchCombined},
|
combined::search::{search_combined_keys as key, SearchCombined},
|
||||||
community::CommunityFollower,
|
community::CommunityFollower,
|
||||||
},
|
},
|
||||||
utils::{actions, actions_alias, functions::coalesce, fuzzy_search, get_conn, DbPool},
|
utils::{
|
||||||
|
actions,
|
||||||
|
actions_alias,
|
||||||
|
functions::coalesce,
|
||||||
|
fuzzy_search,
|
||||||
|
get_conn,
|
||||||
|
DbPool,
|
||||||
|
ReverseTimestampKey,
|
||||||
|
},
|
||||||
InternalToCombinedView,
|
InternalToCombinedView,
|
||||||
ListingType,
|
ListingType,
|
||||||
|
SearchSortType,
|
||||||
SearchType,
|
SearchType,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
use SearchSortType::*;
|
||||||
|
|
||||||
impl SearchCombinedPaginationCursor {
|
impl SearchCombinedPaginationCursor {
|
||||||
// get cursor for page that starts immediately after the given post
|
// get cursor for page that starts immediately after the given post
|
||||||
|
@ -96,8 +106,7 @@ pub struct SearchCombinedQuery {
|
||||||
pub community_id: Option<CommunityId>,
|
pub community_id: Option<CommunityId>,
|
||||||
pub creator_id: Option<PersonId>,
|
pub creator_id: Option<PersonId>,
|
||||||
pub type_: Option<SearchType>,
|
pub type_: Option<SearchType>,
|
||||||
// TODO sorts need to be added
|
pub sort: Option<SearchSortType>,
|
||||||
// pub sort: Option<PostSortType>,
|
|
||||||
pub listing_type: Option<ListingType>,
|
pub listing_type: Option<ListingType>,
|
||||||
pub title_only: Option<bool>,
|
pub title_only: Option<bool>,
|
||||||
pub post_url_only: Option<bool>,
|
pub post_url_only: Option<bool>,
|
||||||
|
@ -314,15 +323,13 @@ impl SearchCombinedQuery {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Type
|
// Type
|
||||||
if let Some(type_) = self.type_ {
|
query = match self.type_.unwrap_or_default() {
|
||||||
query = match type_ {
|
|
||||||
SearchType::All => query,
|
SearchType::All => query,
|
||||||
SearchType::Posts => query.filter(search_combined::post_id.is_not_null()),
|
SearchType::Posts => query.filter(search_combined::post_id.is_not_null()),
|
||||||
SearchType::Comments => query.filter(search_combined::comment_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::Communities => query.filter(search_combined::community_id.is_not_null()),
|
||||||
SearchType::Users => query.filter(search_combined::person_id.is_not_null()),
|
SearchType::Users => query.filter(search_combined::person_id.is_not_null()),
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// Listing type
|
// Listing type
|
||||||
let is_subscribed = community_actions::followed.is_not_null();
|
let is_subscribed = community_actions::followed.is_not_null();
|
||||||
|
@ -359,11 +366,13 @@ impl SearchCombinedQuery {
|
||||||
query = query.after(page_after);
|
query = query.after(page_after);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sorting by published
|
query = match self.sort.unwrap_or_default() {
|
||||||
query = query
|
New => query.then_desc(key::published),
|
||||||
.then_desc(key::published)
|
Old => query.then_desc(ReverseTimestampKey(key::published)),
|
||||||
// Tie breaker
|
Top => query.then_desc(key::score),
|
||||||
.then_desc(key::id);
|
};
|
||||||
|
// finally use unique id as tie breaker
|
||||||
|
query = query.then_desc(key::id);
|
||||||
|
|
||||||
let res = query.load::<SearchCombinedViewInternal>(conn).await?;
|
let res = query.load::<SearchCombinedViewInternal>(conn).await?;
|
||||||
|
|
||||||
|
@ -479,6 +488,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
traits::{Crud, Likeable},
|
traits::{Crud, Likeable},
|
||||||
utils::{build_db_pool_for_tests, DbPool},
|
utils::{build_db_pool_for_tests, DbPool},
|
||||||
|
SearchSortType,
|
||||||
SearchType,
|
SearchType,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
@ -504,6 +514,9 @@ mod tests {
|
||||||
async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
|
async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
|
||||||
let instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
let instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||||
|
|
||||||
|
let sara_form = PersonInsertForm::test_form(instance.id, "sara_pcv");
|
||||||
|
let sara = Person::create(pool, &sara_form).await?;
|
||||||
|
|
||||||
let timmy_form = PersonInsertForm::test_form(instance.id, "timmy_pcv");
|
let timmy_form = PersonInsertForm::test_form(instance.id, "timmy_pcv");
|
||||||
let timmy = Person::create(pool, &timmy_form).await?;
|
let timmy = Person::create(pool, &timmy_form).await?;
|
||||||
let timmy_local_user_form = LocalUserInsertForm::test_form(timmy.id);
|
let timmy_local_user_form = LocalUserInsertForm::test_form(timmy.id);
|
||||||
|
@ -515,9 +528,6 @@ mod tests {
|
||||||
counts: Default::default(),
|
counts: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let sara_form = PersonInsertForm::test_form(instance.id, "sara_pcv");
|
|
||||||
let sara = Person::create(pool, &sara_form).await?;
|
|
||||||
|
|
||||||
let community_form = CommunityInsertForm {
|
let community_form = CommunityInsertForm {
|
||||||
description: Some("ask lemmy things".into()),
|
description: Some("ask lemmy things".into()),
|
||||||
..CommunityInsertForm::new(
|
..CommunityInsertForm::new(
|
||||||
|
@ -685,13 +695,13 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let SearchCombinedView::Person(v) = &search[8] {
|
if let SearchCombinedView::Person(v) = &search[8] {
|
||||||
assert_eq!(data.sara.id, v.person.id);
|
assert_eq!(data.timmy.id, v.person.id);
|
||||||
} else {
|
} else {
|
||||||
panic!("wrong type");
|
panic!("wrong type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let SearchCombinedView::Person(v) = &search[9] {
|
if let SearchCombinedView::Person(v) = &search[9] {
|
||||||
assert_eq!(data.timmy.id, v.person.id);
|
assert_eq!(data.sara.id, v.person.id);
|
||||||
} else {
|
} else {
|
||||||
panic!("wrong type");
|
panic!("wrong type");
|
||||||
}
|
}
|
||||||
|
@ -743,6 +753,21 @@ mod tests {
|
||||||
|
|
||||||
assert_length!(1, search_disliked_only);
|
assert_length!(1, search_disliked_only);
|
||||||
|
|
||||||
|
// Test sorts
|
||||||
|
// Test Old sort
|
||||||
|
let search_old_sort = SearchCombinedQuery {
|
||||||
|
sort: Some(SearchSortType::Old),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.list(pool, &Some(data.timmy_view.clone()))
|
||||||
|
.await?;
|
||||||
|
if let SearchCombinedView::Person(v) = &search_old_sort[0] {
|
||||||
|
assert_eq!(data.sara.id, v.person.id);
|
||||||
|
} else {
|
||||||
|
panic!("wrong type");
|
||||||
|
}
|
||||||
|
assert_length!(10, search_old_sort);
|
||||||
|
|
||||||
// Remove a post and delete a comment
|
// Remove a post and delete a comment
|
||||||
Post::update(
|
Post::update(
|
||||||
pool,
|
pool,
|
||||||
|
@ -865,13 +890,13 @@ mod tests {
|
||||||
|
|
||||||
// Make sure the types are correct
|
// Make sure the types are correct
|
||||||
if let SearchCombinedView::Person(v) = &person_search[0] {
|
if let SearchCombinedView::Person(v) = &person_search[0] {
|
||||||
assert_eq!(data.sara.id, v.person.id);
|
assert_eq!(data.timmy.id, v.person.id);
|
||||||
} else {
|
} else {
|
||||||
panic!("wrong type");
|
panic!("wrong type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let SearchCombinedView::Person(v) = &person_search[1] {
|
if let SearchCombinedView::Person(v) = &person_search[1] {
|
||||||
assert_eq!(data.timmy.id, v.person.id);
|
assert_eq!(data.sara.id, v.person.id);
|
||||||
} else {
|
} else {
|
||||||
panic!("wrong type");
|
panic!("wrong type");
|
||||||
}
|
}
|
||||||
|
@ -907,6 +932,23 @@ mod tests {
|
||||||
panic!("wrong type");
|
panic!("wrong type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test Top sorting (uses post score)
|
||||||
|
let person_search_sort_top = SearchCombinedQuery {
|
||||||
|
type_: Some(SearchType::Users),
|
||||||
|
sort: Some(SearchSortType::Top),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.list(pool, &None)
|
||||||
|
.await?;
|
||||||
|
assert_length!(2, person_search_sort_top);
|
||||||
|
|
||||||
|
// Sara should be first, as she has a higher score
|
||||||
|
if let SearchCombinedView::Person(v) = &person_search_sort_top[0] {
|
||||||
|
assert_eq!(data.sara.id, v.person.id);
|
||||||
|
} else {
|
||||||
|
panic!("wrong type");
|
||||||
|
}
|
||||||
|
|
||||||
cleanup(data, pool).await?;
|
cleanup(data, pool).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1020,6 +1062,24 @@ mod tests {
|
||||||
// Should be zero because you disliked your own post
|
// Should be zero because you disliked your own post
|
||||||
assert_length!(0, post_search_disliked_only);
|
assert_length!(0, post_search_disliked_only);
|
||||||
|
|
||||||
|
// Test top sort
|
||||||
|
let post_search_sort_top = SearchCombinedQuery {
|
||||||
|
type_: Some(SearchType::Posts),
|
||||||
|
sort: Some(SearchSortType::Top),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.list(pool, &None)
|
||||||
|
.await?;
|
||||||
|
assert_length!(3, post_search_sort_top);
|
||||||
|
|
||||||
|
// Timmy_post_2 has a dislike, so it should be last
|
||||||
|
if let SearchCombinedView::Post(v) = &post_search_sort_top[2] {
|
||||||
|
assert_eq!(data.timmy_post_2.id, v.post.id);
|
||||||
|
assert_eq!(data.community.id, v.community.id);
|
||||||
|
} else {
|
||||||
|
panic!("wrong type");
|
||||||
|
}
|
||||||
|
|
||||||
cleanup(data, pool).await?;
|
cleanup(data, pool).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1108,6 +1168,25 @@ mod tests {
|
||||||
|
|
||||||
assert_length!(1, comment_search_disliked_only);
|
assert_length!(1, comment_search_disliked_only);
|
||||||
|
|
||||||
|
// Test top sort
|
||||||
|
let comment_search_sort_top = SearchCombinedQuery {
|
||||||
|
type_: Some(SearchType::Comments),
|
||||||
|
sort: Some(SearchSortType::Top),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.list(pool, &None)
|
||||||
|
.await?;
|
||||||
|
assert_length!(3, comment_search_sort_top);
|
||||||
|
|
||||||
|
// Sara comment 2 is disliked, so should be last
|
||||||
|
if let SearchCombinedView::Comment(v) = &comment_search_sort_top[2] {
|
||||||
|
assert_eq!(data.sara_comment_2.id, v.comment.id);
|
||||||
|
assert_eq!(data.timmy_post_2.id, v.post.id);
|
||||||
|
assert_eq!(data.community.id, v.community.id);
|
||||||
|
} else {
|
||||||
|
panic!("wrong type");
|
||||||
|
}
|
||||||
|
|
||||||
cleanup(data, pool).await?;
|
cleanup(data, pool).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "lemmy_db_views_actor"
|
|
||||||
version.workspace = true
|
|
||||||
edition.workspace = true
|
|
||||||
description.workspace = true
|
|
||||||
license.workspace = true
|
|
||||||
homepage.workspace = true
|
|
||||||
documentation.workspace = true
|
|
||||||
repository.workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
doctest = false
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[features]
|
|
||||||
full = [
|
|
||||||
"lemmy_db_schema/full",
|
|
||||||
"lemmy_utils/full",
|
|
||||||
"i-love-jesus",
|
|
||||||
"diesel",
|
|
||||||
"diesel-async",
|
|
||||||
"ts-rs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
lemmy_db_schema = { workspace = true }
|
|
||||||
diesel = { workspace = true, features = [
|
|
||||||
"chrono",
|
|
||||||
"postgres",
|
|
||||||
"serde_json",
|
|
||||||
], optional = true }
|
|
||||||
diesel-async = { workspace = true, features = [
|
|
||||||
"deadpool",
|
|
||||||
"postgres",
|
|
||||||
], optional = true }
|
|
||||||
serde = { workspace = true }
|
|
||||||
serde_with = { workspace = true }
|
|
||||||
ts-rs = { workspace = true, optional = true }
|
|
||||||
chrono.workspace = true
|
|
||||||
strum = { workspace = true }
|
|
||||||
lemmy_utils = { workspace = true, optional = true }
|
|
||||||
i-love-jesus = { workspace = true, optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
serial_test = { workspace = true }
|
|
||||||
tokio = { workspace = true }
|
|
||||||
pretty_assertions = { workspace = true }
|
|
||||||
url.workspace = true
|
|
|
@ -1,15 +0,0 @@
|
||||||
#[cfg(feature = "full")]
|
|
||||||
pub mod community_follower_view;
|
|
||||||
#[cfg(feature = "full")]
|
|
||||||
pub mod community_moderator_view;
|
|
||||||
#[cfg(feature = "full")]
|
|
||||||
pub mod community_person_ban_view;
|
|
||||||
#[cfg(feature = "full")]
|
|
||||||
pub mod community_view;
|
|
||||||
#[cfg(feature = "full")]
|
|
||||||
pub mod inbox_combined_view;
|
|
||||||
#[cfg(feature = "full")]
|
|
||||||
pub mod person_view;
|
|
||||||
#[cfg(feature = "full")]
|
|
||||||
pub mod private_message_view;
|
|
||||||
pub mod structs;
|
|
|
@ -1,47 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "lemmy_db_views_moderator"
|
|
||||||
version.workspace = true
|
|
||||||
edition.workspace = true
|
|
||||||
description.workspace = true
|
|
||||||
license.workspace = true
|
|
||||||
homepage.workspace = true
|
|
||||||
documentation.workspace = true
|
|
||||||
repository.workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
doctest = false
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[features]
|
|
||||||
full = [
|
|
||||||
"lemmy_db_schema/full",
|
|
||||||
"lemmy_utils",
|
|
||||||
"i-love-jesus",
|
|
||||||
"diesel",
|
|
||||||
"diesel-async",
|
|
||||||
"ts-rs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
lemmy_db_schema = { workspace = true }
|
|
||||||
lemmy_utils = { workspace = true, optional = true }
|
|
||||||
i-love-jesus = { workspace = true, optional = true }
|
|
||||||
diesel = { workspace = true, features = [
|
|
||||||
"chrono",
|
|
||||||
"postgres",
|
|
||||||
"serde_json",
|
|
||||||
], optional = true }
|
|
||||||
diesel-async = { workspace = true, features = [
|
|
||||||
"deadpool",
|
|
||||||
"postgres",
|
|
||||||
], optional = true }
|
|
||||||
serde = { workspace = true }
|
|
||||||
serde_with = { workspace = true }
|
|
||||||
ts-rs = { workspace = true, optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
serial_test = { workspace = true }
|
|
||||||
tokio = { workspace = true }
|
|
||||||
pretty_assertions = { workspace = true }
|
|
|
@ -1,332 +0,0 @@
|
||||||
#[cfg(feature = "full")]
|
|
||||||
use diesel::Queryable;
|
|
||||||
use lemmy_db_schema::source::{
|
|
||||||
comment::Comment,
|
|
||||||
community::Community,
|
|
||||||
instance::Instance,
|
|
||||||
mod_log::{
|
|
||||||
admin::{
|
|
||||||
AdminAllowInstance,
|
|
||||||
AdminBlockInstance,
|
|
||||||
AdminPurgeComment,
|
|
||||||
AdminPurgeCommunity,
|
|
||||||
AdminPurgePerson,
|
|
||||||
AdminPurgePost,
|
|
||||||
},
|
|
||||||
moderator::{
|
|
||||||
ModAdd,
|
|
||||||
ModAddCommunity,
|
|
||||||
ModBan,
|
|
||||||
ModBanFromCommunity,
|
|
||||||
ModFeaturePost,
|
|
||||||
ModHideCommunity,
|
|
||||||
ModLockPost,
|
|
||||||
ModRemoveComment,
|
|
||||||
ModRemoveCommunity,
|
|
||||||
ModRemovePost,
|
|
||||||
ModTransferCommunity,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
person::Person,
|
|
||||||
post::Post,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use serde_with::skip_serializing_none;
|
|
||||||
#[cfg(feature = "full")]
|
|
||||||
use ts_rs::TS;
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When someone is added as a community moderator.
|
|
||||||
pub struct ModAddCommunityView {
|
|
||||||
pub mod_add_community: ModAddCommunity,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub moderator: Option<Person>,
|
|
||||||
pub community: Community,
|
|
||||||
pub other_person: Person,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When someone is added as a site moderator.
|
|
||||||
pub struct ModAddView {
|
|
||||||
pub mod_add: ModAdd,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub moderator: Option<Person>,
|
|
||||||
pub other_person: Person,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When someone is banned from a community.
|
|
||||||
pub struct ModBanFromCommunityView {
|
|
||||||
pub mod_ban_from_community: ModBanFromCommunity,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub moderator: Option<Person>,
|
|
||||||
pub community: Community,
|
|
||||||
pub other_person: Person,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When someone is banned from the site.
|
|
||||||
pub struct ModBanView {
|
|
||||||
pub mod_ban: ModBan,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub moderator: Option<Person>,
|
|
||||||
pub other_person: Person,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When a community is hidden from public view.
|
|
||||||
pub struct ModHideCommunityView {
|
|
||||||
pub mod_hide_community: ModHideCommunity,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub admin: Option<Person>,
|
|
||||||
pub community: Community,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When a moderator locks a post (prevents new comments being made).
|
|
||||||
pub struct ModLockPostView {
|
|
||||||
pub mod_lock_post: ModLockPost,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub moderator: Option<Person>,
|
|
||||||
pub other_person: Person,
|
|
||||||
pub post: Post,
|
|
||||||
pub community: Community,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When a moderator removes a comment.
|
|
||||||
pub struct ModRemoveCommentView {
|
|
||||||
pub mod_remove_comment: ModRemoveComment,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub moderator: Option<Person>,
|
|
||||||
pub other_person: Person,
|
|
||||||
pub comment: Comment,
|
|
||||||
pub post: Post,
|
|
||||||
pub community: Community,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When a moderator removes a community.
|
|
||||||
pub struct ModRemoveCommunityView {
|
|
||||||
pub mod_remove_community: ModRemoveCommunity,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub moderator: Option<Person>,
|
|
||||||
pub community: Community,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When a moderator removes a post.
|
|
||||||
pub struct ModRemovePostView {
|
|
||||||
pub mod_remove_post: ModRemovePost,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub moderator: Option<Person>,
|
|
||||||
pub other_person: Person,
|
|
||||||
pub post: Post,
|
|
||||||
pub community: Community,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When a moderator features a post on a community (pins it to the top).
|
|
||||||
pub struct ModFeaturePostView {
|
|
||||||
pub mod_feature_post: ModFeaturePost,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub moderator: Option<Person>,
|
|
||||||
pub other_person: Person,
|
|
||||||
pub post: Post,
|
|
||||||
pub community: Community,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When a moderator transfers a community to a new owner.
|
|
||||||
pub struct ModTransferCommunityView {
|
|
||||||
pub mod_transfer_community: ModTransferCommunity,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub moderator: Option<Person>,
|
|
||||||
pub community: Community,
|
|
||||||
pub other_person: Person,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When an admin purges a comment.
|
|
||||||
pub struct AdminPurgeCommentView {
|
|
||||||
pub admin_purge_comment: AdminPurgeComment,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub admin: Option<Person>,
|
|
||||||
pub post: Post,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When an admin purges a community.
|
|
||||||
pub struct AdminPurgeCommunityView {
|
|
||||||
pub admin_purge_community: AdminPurgeCommunity,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub admin: Option<Person>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When an admin purges a person.
|
|
||||||
pub struct AdminPurgePersonView {
|
|
||||||
pub admin_purge_person: AdminPurgePerson,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub admin: Option<Person>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When an admin purges a post.
|
|
||||||
pub struct AdminPurgePostView {
|
|
||||||
pub admin_purge_post: AdminPurgePost,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub admin: Option<Person>,
|
|
||||||
pub community: Community,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When an admin purges a post.
|
|
||||||
pub struct AdminBlockInstanceView {
|
|
||||||
pub admin_block_instance: AdminBlockInstance,
|
|
||||||
pub instance: Instance,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub admin: Option<Person>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// When an admin purges a post.
|
|
||||||
pub struct AdminAllowInstanceView {
|
|
||||||
pub admin_allow_instance: AdminAllowInstance,
|
|
||||||
pub instance: Instance,
|
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
|
||||||
pub admin: Option<Person>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// like PaginationCursor but for the modlog_combined
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
pub struct ModlogCombinedPaginationCursor(pub String);
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(Queryable))]
|
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
|
||||||
/// A combined modlog view
|
|
||||||
pub struct ModlogCombinedViewInternal {
|
|
||||||
// Specific
|
|
||||||
pub admin_allow_instance: Option<AdminAllowInstance>,
|
|
||||||
pub admin_block_instance: Option<AdminBlockInstance>,
|
|
||||||
pub admin_purge_comment: Option<AdminPurgeComment>,
|
|
||||||
pub admin_purge_community: Option<AdminPurgeCommunity>,
|
|
||||||
pub admin_purge_person: Option<AdminPurgePerson>,
|
|
||||||
pub admin_purge_post: Option<AdminPurgePost>,
|
|
||||||
pub mod_add: Option<ModAdd>,
|
|
||||||
pub mod_add_community: Option<ModAddCommunity>,
|
|
||||||
pub mod_ban: Option<ModBan>,
|
|
||||||
pub mod_ban_from_community: Option<ModBanFromCommunity>,
|
|
||||||
pub mod_feature_post: Option<ModFeaturePost>,
|
|
||||||
pub mod_hide_community: Option<ModHideCommunity>,
|
|
||||||
pub mod_lock_post: Option<ModLockPost>,
|
|
||||||
pub mod_remove_comment: Option<ModRemoveComment>,
|
|
||||||
pub mod_remove_community: Option<ModRemoveCommunity>,
|
|
||||||
pub mod_remove_post: Option<ModRemovePost>,
|
|
||||||
pub mod_transfer_community: Option<ModTransferCommunity>,
|
|
||||||
// Specific fields
|
|
||||||
|
|
||||||
// Shared
|
|
||||||
pub moderator: Option<Person>,
|
|
||||||
pub other_person: Option<Person>,
|
|
||||||
pub instance: Option<Instance>,
|
|
||||||
pub community: Option<Community>,
|
|
||||||
pub post: Option<Post>,
|
|
||||||
pub comment: Option<Comment>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
// Use serde's internal tagging, to work easier with javascript libraries
|
|
||||||
#[serde(tag = "type_")]
|
|
||||||
pub enum ModlogCombinedView {
|
|
||||||
AdminAllowInstance(AdminAllowInstanceView),
|
|
||||||
AdminBlockInstance(AdminBlockInstanceView),
|
|
||||||
AdminPurgeComment(AdminPurgeCommentView),
|
|
||||||
AdminPurgeCommunity(AdminPurgeCommunityView),
|
|
||||||
AdminPurgePerson(AdminPurgePersonView),
|
|
||||||
AdminPurgePost(AdminPurgePostView),
|
|
||||||
ModAdd(ModAddView),
|
|
||||||
ModAddCommunity(ModAddCommunityView),
|
|
||||||
ModBan(ModBanView),
|
|
||||||
ModBanFromCommunity(ModBanFromCommunityView),
|
|
||||||
ModFeaturePost(ModFeaturePostView),
|
|
||||||
ModHideCommunity(ModHideCommunityView),
|
|
||||||
ModLockPost(ModLockPostView),
|
|
||||||
ModRemoveComment(ModRemoveCommentView),
|
|
||||||
ModRemoveCommunity(ModRemoveCommunityView),
|
|
||||||
ModRemovePost(ModRemovePostView),
|
|
||||||
ModTransferCommunity(ModTransferCommunityView),
|
|
||||||
}
|
|
|
@ -3,15 +3,12 @@
|
||||||
CREATE TABLE search_combined (
|
CREATE TABLE search_combined (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
published timestamptz NOT NULL,
|
published timestamptz NOT NULL,
|
||||||
-- TODO Need to figure out all the possible sort types, unified into SearchSortType
|
-- This is used for the top sort
|
||||||
-- This is difficult because other than published, there is no unified way to sort them.
|
-- For persons: its post score
|
||||||
--
|
-- For comments: score,
|
||||||
-- All have published.
|
-- For posts: score,
|
||||||
-- post and comment have top and time-limited scores and ranks.
|
-- For community: users active monthly
|
||||||
-- persons have post and comment counts, and scores (not time-limited).
|
score bigint NOT NULL DEFAULT 0,
|
||||||
-- communities have subscribers, post and comment counts, and active users per X time.
|
|
||||||
--
|
|
||||||
-- I'm thinking just published and score (and use active_monthly users as the community score), is the best way to start.
|
|
||||||
post_id int UNIQUE REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE,
|
post_id int UNIQUE REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
comment_id int UNIQUE REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE,
|
comment_id int UNIQUE REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
community_id int UNIQUE REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE,
|
community_id int UNIQUE REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
|
@ -25,40 +22,48 @@ CREATE INDEX idx_search_combined_published ON search_combined (published DESC, i
|
||||||
CREATE INDEX idx_search_combined_published_asc ON search_combined (reverse_timestamp_sort (published) DESC, id DESC);
|
CREATE INDEX idx_search_combined_published_asc ON search_combined (reverse_timestamp_sort (published) DESC, id DESC);
|
||||||
|
|
||||||
-- Updating the history
|
-- Updating the history
|
||||||
INSERT INTO search_combined (published, post_id, comment_id, community_id, person_id)
|
INSERT INTO search_combined (published, score, post_id, comment_id, community_id, person_id)
|
||||||
SELECT
|
SELECT
|
||||||
published,
|
p.published,
|
||||||
|
score,
|
||||||
id,
|
id,
|
||||||
NULL::int,
|
NULL::int,
|
||||||
NULL::int,
|
NULL::int,
|
||||||
NULL::int
|
NULL::int
|
||||||
FROM
|
FROM
|
||||||
post
|
post p
|
||||||
|
INNER JOIN post_aggregates pa ON p.id = pa.post_id
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT
|
SELECT
|
||||||
published,
|
c.published,
|
||||||
|
score,
|
||||||
NULL::int,
|
NULL::int,
|
||||||
id,
|
id,
|
||||||
NULL::int,
|
NULL::int,
|
||||||
NULL::int
|
NULL::int
|
||||||
FROM
|
FROM
|
||||||
comment
|
comment c
|
||||||
|
INNER JOIN comment_aggregates ca ON c.id = ca.comment_id
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT
|
SELECT
|
||||||
published,
|
c.published,
|
||||||
|
users_active_month,
|
||||||
NULL::int,
|
NULL::int,
|
||||||
NULL::int,
|
NULL::int,
|
||||||
id,
|
id,
|
||||||
NULL::int
|
NULL::int
|
||||||
FROM
|
FROM
|
||||||
community
|
community c
|
||||||
|
INNER JOIN community_aggregates ca ON c.id = ca.community_id
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT
|
SELECT
|
||||||
published,
|
p.published,
|
||||||
|
post_score,
|
||||||
NULL::int,
|
NULL::int,
|
||||||
NULL::int,
|
NULL::int,
|
||||||
NULL::int,
|
NULL::int,
|
||||||
id
|
id
|
||||||
FROM
|
FROM
|
||||||
person;
|
person p
|
||||||
|
INNER JOIN person_aggregates pa ON p.id = pa.person_id;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue