mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-12-13 06:08:20 +00:00
Start working on profile combined
This commit is contained in:
parent
921d53227c
commit
724856d684
|
@ -185,6 +185,12 @@ pub struct DbUrl(pub(crate) Box<Url>);
|
||||||
/// The report combined id
|
/// The report combined id
|
||||||
pub struct ReportCombinedId(i32);
|
pub struct ReportCombinedId(i32);
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||||
|
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
/// The profile combined id
|
||||||
|
pub struct ProfileCombinedId(i32);
|
||||||
|
|
||||||
impl DbUrl {
|
impl DbUrl {
|
||||||
pub fn inner(&self) -> &Url {
|
pub fn inner(&self) -> &Url {
|
||||||
&self.0
|
&self.0
|
||||||
|
|
|
@ -856,6 +856,15 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
profile_combined (id) {
|
||||||
|
id -> Int4,
|
||||||
|
published -> Timestamptz,
|
||||||
|
post_id -> Nullable<Int4>,
|
||||||
|
comment_id -> Nullable<Int4>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
received_activity (ap_id) {
|
received_activity (ap_id) {
|
||||||
ap_id -> Text,
|
ap_id -> Text,
|
||||||
|
@ -1043,6 +1052,8 @@ diesel::joinable!(post_aggregates -> person (creator_id));
|
||||||
diesel::joinable!(post_aggregates -> post (post_id));
|
diesel::joinable!(post_aggregates -> post (post_id));
|
||||||
diesel::joinable!(post_report -> post (post_id));
|
diesel::joinable!(post_report -> post (post_id));
|
||||||
diesel::joinable!(private_message_report -> private_message (private_message_id));
|
diesel::joinable!(private_message_report -> private_message (private_message_id));
|
||||||
|
diesel::joinable!(profile_combined -> comment (comment_id));
|
||||||
|
diesel::joinable!(profile_combined -> post (post_id));
|
||||||
diesel::joinable!(registration_application -> local_user (local_user_id));
|
diesel::joinable!(registration_application -> local_user (local_user_id));
|
||||||
diesel::joinable!(registration_application -> person (admin_id));
|
diesel::joinable!(registration_application -> person (admin_id));
|
||||||
diesel::joinable!(report_combined -> comment_report (comment_report_id));
|
diesel::joinable!(report_combined -> comment_report (comment_report_id));
|
||||||
|
@ -1113,6 +1124,7 @@ diesel::allow_tables_to_appear_in_same_query!(
|
||||||
post_report,
|
post_report,
|
||||||
private_message,
|
private_message,
|
||||||
private_message_report,
|
private_message_report,
|
||||||
|
profile_combined,
|
||||||
received_activity,
|
received_activity,
|
||||||
registration_application,
|
registration_application,
|
||||||
remote_image,
|
remote_image,
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
|
pub mod profile;
|
||||||
pub mod report;
|
pub mod report;
|
||||||
|
|
30
crates/db_schema/src/source/combined/profile.rs
Normal file
30
crates/db_schema/src/source/combined/profile.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use crate::newtypes::{CommentId, PostId, ProfileCombinedId};
|
||||||
|
#[cfg(feature = "full")]
|
||||||
|
use crate::schema::profile_combined;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
#[cfg(feature = "full")]
|
||||||
|
use i_love_jesus::CursorKeysModule;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_with::skip_serializing_none;
|
||||||
|
#[cfg(feature = "full")]
|
||||||
|
use ts_rs::TS;
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Clone)]
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Identifiable, Queryable, Selectable, TS, CursorKeysModule)
|
||||||
|
)]
|
||||||
|
#[cfg_attr(feature = "full", diesel(table_name = profile_combined))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
#[cfg_attr(feature = "full", cursor_keys_module(name = profile_combined_keys))]
|
||||||
|
/// A combined profile table.
|
||||||
|
pub struct ProfileCombined {
|
||||||
|
pub id: ProfileCombinedId,
|
||||||
|
pub published: DateTime<Utc>,
|
||||||
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
pub post_id: Option<PostId>,
|
||||||
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
pub comment_id: Option<CommentId>,
|
||||||
|
}
|
|
@ -20,6 +20,8 @@ pub mod private_message_report_view;
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
pub mod private_message_view;
|
pub mod private_message_view;
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
|
pub mod profile_combined_view;
|
||||||
|
#[cfg(feature = "full")]
|
||||||
pub mod registration_application_view;
|
pub mod registration_application_view;
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
pub mod report_combined_view;
|
pub mod report_combined_view;
|
||||||
|
|
304
crates/db_views/src/profile_combined_view.rs
Normal file
304
crates/db_views/src/profile_combined_view.rs
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
use crate::structs::{
|
||||||
|
CommentView,
|
||||||
|
LocalUserView,
|
||||||
|
PostView,
|
||||||
|
ProfileCombinedPaginationCursor,
|
||||||
|
ProfileCombinedView,
|
||||||
|
ProfileCombinedViewInternal,
|
||||||
|
};
|
||||||
|
use diesel::{
|
||||||
|
result::Error,
|
||||||
|
BoolExpressionMethods,
|
||||||
|
ExpressionMethods,
|
||||||
|
JoinOnDsl,
|
||||||
|
NullableExpressionMethods,
|
||||||
|
QueryDsl,
|
||||||
|
SelectableHelper,
|
||||||
|
};
|
||||||
|
use diesel_async::RunQueryDsl;
|
||||||
|
use i_love_jesus::PaginatedQueryBuilder;
|
||||||
|
use lemmy_db_schema::{
|
||||||
|
aliases::{self, creator_community_actions},
|
||||||
|
newtypes::CommunityId,
|
||||||
|
schema::{
|
||||||
|
comment,
|
||||||
|
comment_actions,
|
||||||
|
comment_aggregates,
|
||||||
|
community,
|
||||||
|
community_actions,
|
||||||
|
local_user,
|
||||||
|
person,
|
||||||
|
person_actions,
|
||||||
|
post,
|
||||||
|
post_actions,
|
||||||
|
post_aggregates,
|
||||||
|
profile_combined,
|
||||||
|
},
|
||||||
|
source::{
|
||||||
|
combined::profile::{profile_combined_keys as key, ProfileCombined},
|
||||||
|
community::CommunityFollower,
|
||||||
|
},
|
||||||
|
utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool, ReverseTimestampKey},
|
||||||
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
|
impl ProfileCombinedPaginationCursor {
|
||||||
|
// get cursor for page that starts immediately after the given post
|
||||||
|
pub fn after_post(view: &ProfileCombinedView) -> ProfileCombinedPaginationCursor {
|
||||||
|
let (prefix, id) = match view {
|
||||||
|
ProfileCombinedView::Comment(v) => ('C', v.comment.id.0),
|
||||||
|
ProfileCombinedView::Post(v) => ('P', v.post.id.0),
|
||||||
|
};
|
||||||
|
// hex encoding to prevent ossification
|
||||||
|
ProfileCombinedPaginationCursor(format!("{prefix}{id:x}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn read(&self, pool: &mut DbPool<'_>) -> Result<PaginationCursorData, Error> {
|
||||||
|
let err_msg = || Error::QueryBuilderError("Could not parse pagination token".into());
|
||||||
|
let mut query = profile_combined::table
|
||||||
|
.select(ProfileCombined::as_select())
|
||||||
|
.into_boxed();
|
||||||
|
let (prefix, id_str) = self.0.split_at_checked(1).ok_or_else(err_msg)?;
|
||||||
|
let id = i32::from_str_radix(id_str, 16).map_err(|_err| err_msg())?;
|
||||||
|
query = match prefix {
|
||||||
|
"C" => query.filter(profile_combined::comment_id.eq(id)),
|
||||||
|
"P" => query.filter(profile_combined::post_id.eq(id)),
|
||||||
|
_ => return Err(err_msg()),
|
||||||
|
};
|
||||||
|
let token = query.first(&mut get_conn(pool).await?).await?;
|
||||||
|
|
||||||
|
Ok(PaginationCursorData(token))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PaginationCursorData(ProfileCombined);
|
||||||
|
|
||||||
|
// TODO check these
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ProfileCombinedQuery {
|
||||||
|
pub community_id: Option<CommunityId>,
|
||||||
|
pub unresolved_only: Option<bool>,
|
||||||
|
pub page_after: Option<PaginationCursorData>,
|
||||||
|
pub page_back: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProfileCombinedQuery {
|
||||||
|
pub async fn list(
|
||||||
|
self,
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
user: &LocalUserView,
|
||||||
|
) -> LemmyResult<Vec<ProfileCombinedView>> {
|
||||||
|
let my_person_id = user.local_user.person_id;
|
||||||
|
// let item_creator = aliases::person1.field(person::id);
|
||||||
|
let item_creator = person::id;
|
||||||
|
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
|
// Notes: since the post_id and comment_id are optional columns,
|
||||||
|
// many joins must use an OR condition.
|
||||||
|
// For example, the creator must be the person table joined to either:
|
||||||
|
// - post.creator_id
|
||||||
|
// - comment.creator_id
|
||||||
|
let mut query = profile_combined::table
|
||||||
|
// The comment
|
||||||
|
.left_join(comment::table.on(profile_combined::comment_id.eq(comment::id.nullable())))
|
||||||
|
// The post
|
||||||
|
.inner_join(
|
||||||
|
post::table.on(
|
||||||
|
profile_combined::post_id
|
||||||
|
.eq(post::id.nullable())
|
||||||
|
.or(comment::post_id.nullable().eq(profile_combined::post_id)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// The item creator
|
||||||
|
.inner_join(
|
||||||
|
person::table.on(
|
||||||
|
post::creator_id
|
||||||
|
.eq(person::id)
|
||||||
|
.or(comment::creator_id.eq(person::id)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// The item creator
|
||||||
|
// You can now use aliases::person1.field(person::id) / item_creator for all the item actions
|
||||||
|
// .inner_join(
|
||||||
|
// aliases::person1.on(
|
||||||
|
// post::creator_id
|
||||||
|
// .eq(item_creator)
|
||||||
|
// .or(comment::creator_id.eq(item_creator)),
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// The community
|
||||||
|
.inner_join(community::table.on(post::community_id.eq(community::id)))
|
||||||
|
.left_join(actions_alias(
|
||||||
|
creator_community_actions,
|
||||||
|
item_creator,
|
||||||
|
post::community_id,
|
||||||
|
))
|
||||||
|
.left_join(
|
||||||
|
local_user::table.on(
|
||||||
|
item_creator
|
||||||
|
.eq(local_user::person_id)
|
||||||
|
.and(local_user::admin.eq(true)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(actions(
|
||||||
|
community_actions::table,
|
||||||
|
Some(my_person_id),
|
||||||
|
post::community_id,
|
||||||
|
))
|
||||||
|
.left_join(actions(post_actions::table, Some(my_person_id), post::id))
|
||||||
|
.left_join(actions(
|
||||||
|
person_actions::table,
|
||||||
|
Some(my_person_id),
|
||||||
|
item_creator,
|
||||||
|
))
|
||||||
|
.left_join(
|
||||||
|
post_aggregates::table
|
||||||
|
.on(profile_combined::post_id.eq(post_aggregates::post_id.nullable())),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
comment_aggregates::table
|
||||||
|
.on(profile_combined::comment_id.eq(comment_aggregates::comment_id.nullable())),
|
||||||
|
)
|
||||||
|
.left_join(actions(
|
||||||
|
comment_actions::table,
|
||||||
|
Some(my_person_id),
|
||||||
|
comment::id,
|
||||||
|
))
|
||||||
|
.select((
|
||||||
|
// Post-specific
|
||||||
|
post::all_columns.nullable(),
|
||||||
|
// post_aggregates::all_columns.nullable(),
|
||||||
|
// coalesce(
|
||||||
|
// post_aggregates::comments.nullable() - post_actions::read_comments_amount.nullable(),
|
||||||
|
// post_aggregates::comments,
|
||||||
|
// )
|
||||||
|
// .nullable(),
|
||||||
|
// post_actions::saved.nullable().is_not_null(),
|
||||||
|
// post_actions::read.nullable().is_not_null(),
|
||||||
|
// post_actions::hidden.nullable().is_not_null(),
|
||||||
|
// post_actions::like_score.nullable(),
|
||||||
|
// // Comment-specific
|
||||||
|
// comment::all_columns.nullable(),
|
||||||
|
// comment_aggregates::all_columns.nullable(),
|
||||||
|
// comment_actions::saved.nullable().is_not_null(),
|
||||||
|
// comment_actions::like_score.nullable(),
|
||||||
|
// // Private-message-specific
|
||||||
|
// private_message_profile::all_columns.nullable(),
|
||||||
|
// private_message::all_columns.nullable(),
|
||||||
|
// // Shared
|
||||||
|
// person::all_columns,
|
||||||
|
// aliases::person1.fields(person::all_columns),
|
||||||
|
// community::all_columns.nullable(),
|
||||||
|
// CommunityFollower::select_subscribed_type(),
|
||||||
|
// aliases::person2.fields(person::all_columns.nullable()),
|
||||||
|
// local_user::admin.nullable().is_not_null(),
|
||||||
|
// creator_community_actions
|
||||||
|
// .field(community_actions::received_ban)
|
||||||
|
// .nullable()
|
||||||
|
// .is_not_null(),
|
||||||
|
// creator_community_actions
|
||||||
|
// .field(community_actions::became_moderator)
|
||||||
|
// .nullable()
|
||||||
|
// .is_not_null(),
|
||||||
|
// person_actions::blocked.nullable().is_not_null(),
|
||||||
|
))
|
||||||
|
.into_boxed();
|
||||||
|
|
||||||
|
if let Some(community_id) = self.community_id {
|
||||||
|
query = query.filter(community::id.eq(community_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If its not an admin, get only the ones you mod
|
||||||
|
if !user.local_user.admin {
|
||||||
|
query = query.filter(community_actions::became_moderator.is_not_null());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut query = PaginatedQueryBuilder::new(query);
|
||||||
|
|
||||||
|
let page_after = self.page_after.map(|c| c.0);
|
||||||
|
|
||||||
|
if self.page_back.unwrap_or_default() {
|
||||||
|
query = query.before(page_after).limit_and_offset_from_end();
|
||||||
|
} else {
|
||||||
|
query = query.after(page_after);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If viewing all profiles, order by newest, but if viewing unresolved only, show the oldest
|
||||||
|
// first (FIFO)
|
||||||
|
if self.unresolved_only.unwrap_or_default() {
|
||||||
|
query = query
|
||||||
|
.filter(
|
||||||
|
post_profile::resolved
|
||||||
|
.eq(false)
|
||||||
|
.or(comment_profile::resolved.eq(false))
|
||||||
|
.or(private_message_profile::resolved.eq(false)),
|
||||||
|
)
|
||||||
|
// TODO: when a `then_asc` method is added, use it here, make the id sort direction match,
|
||||||
|
// and remove the separate index; unless additional columns are added to this sort
|
||||||
|
.then_desc(ReverseTimestampKey(key::published));
|
||||||
|
} else {
|
||||||
|
query = query.then_desc(key::published);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tie breaker
|
||||||
|
query = query.then_desc(key::id);
|
||||||
|
|
||||||
|
let res = query.load::<ProfileCombinedViewInternal>(conn).await?;
|
||||||
|
|
||||||
|
// Map the query results to the enum
|
||||||
|
let out = res.into_iter().filter_map(map_to_enum).collect();
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maps the combined DB row to an enum
|
||||||
|
fn map_to_enum(view: ProfileCombinedViewInternal) -> Option<ProfileCombinedView> {
|
||||||
|
// Use for a short alias
|
||||||
|
let v = view;
|
||||||
|
|
||||||
|
if let (Some(post), Some(community), Some(unread_comments), Some(counts)) =
|
||||||
|
(v.post, v.community, v.post_unread_comments, v.post_counts)
|
||||||
|
{
|
||||||
|
Some(ProfileCombinedView::Post(PostView {
|
||||||
|
post,
|
||||||
|
community,
|
||||||
|
unread_comments,
|
||||||
|
counts,
|
||||||
|
creator: v.item_creator,
|
||||||
|
creator_banned_from_community: v.item_creator_banned_from_community,
|
||||||
|
creator_is_moderator: v.item_creator_is_moderator,
|
||||||
|
creator_is_admin: v.item_creator_is_admin,
|
||||||
|
creator_blocked: v.item_creator_blocked,
|
||||||
|
subscribed: v.subscribed,
|
||||||
|
saved: v.post_saved,
|
||||||
|
read: v.post_read,
|
||||||
|
hidden: v.post_hidden,
|
||||||
|
my_vote: v.my_post_vote,
|
||||||
|
}))
|
||||||
|
} else if let (Some(comment), Some(counts), Some(post), Some(community)) = (
|
||||||
|
v.comment,
|
||||||
|
v.comment_counts,
|
||||||
|
v.post.clone(),
|
||||||
|
v.community.clone(),
|
||||||
|
) {
|
||||||
|
Some(ProfileCombinedView::Comment(CommentView {
|
||||||
|
comment,
|
||||||
|
counts,
|
||||||
|
post,
|
||||||
|
community,
|
||||||
|
creator: v.item_creator,
|
||||||
|
creator_banned_from_community: v.item_creator_banned_from_community,
|
||||||
|
creator_is_moderator: v.item_creator_is_moderator,
|
||||||
|
creator_is_admin: v.item_creator_is_admin,
|
||||||
|
creator_blocked: v.item_creator_blocked,
|
||||||
|
subscribed: v.subscribed,
|
||||||
|
saved: v.comment_saved,
|
||||||
|
my_vote: v.my_comment_vote,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
|
@ -132,6 +132,12 @@ pub struct PaginationCursor(pub String);
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
pub struct ReportCombinedPaginationCursor(pub String);
|
pub struct ReportCombinedPaginationCursor(pub String);
|
||||||
|
|
||||||
|
/// like PaginationCursor but for the profile_combined table
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
#[cfg_attr(feature = "full", derive(ts_rs::TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
pub struct ProfileCombinedPaginationCursor(pub String);
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
||||||
|
@ -289,3 +295,44 @@ pub enum ReportCombinedView {
|
||||||
Comment(CommentReportView),
|
Comment(CommentReportView),
|
||||||
PrivateMessage(PrivateMessageReportView),
|
PrivateMessage(PrivateMessageReportView),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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 profile view
|
||||||
|
pub struct ProfileCombinedViewInternal {
|
||||||
|
// Post-specific
|
||||||
|
pub post_counts: PostAggregates,
|
||||||
|
pub post_unread_comments: i64,
|
||||||
|
pub post_saved: bool,
|
||||||
|
pub post_read: bool,
|
||||||
|
pub post_hidden: bool,
|
||||||
|
pub my_post_vote: Option<i16>,
|
||||||
|
pub image_details: Option<ImageDetails>,
|
||||||
|
// Comment-specific
|
||||||
|
pub comment: Comment,
|
||||||
|
pub comment_counts: CommentAggregates,
|
||||||
|
pub comment_saved: bool,
|
||||||
|
pub my_comment_vote: Option<i16>,
|
||||||
|
// Shared
|
||||||
|
pub post: Post,
|
||||||
|
pub community: Community,
|
||||||
|
pub item_creator: Person,
|
||||||
|
pub subscribed: SubscribedType,
|
||||||
|
pub item_creator_is_admin: bool,
|
||||||
|
pub item_creator_is_moderator: bool,
|
||||||
|
pub item_creator_banned_from_community: bool,
|
||||||
|
pub item_creator_blocked: bool,
|
||||||
|
pub item_saved: bool,
|
||||||
|
pub banned_from_community: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 ProfileCombinedView {
|
||||||
|
Post(PostView),
|
||||||
|
Comment(CommentView),
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
DROP TABLE profile_combined;
|
|
@ -0,0 +1,29 @@
|
||||||
|
-- Creates combined tables for
|
||||||
|
-- Profile: (comment, post)
|
||||||
|
CREATE TABLE profile_combined (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
published timestamptz NOT NULL,
|
||||||
|
post_id int UNIQUE REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
|
comment_id int UNIQUE REFERENCES comment ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
|
-- Make sure only one of the columns is not null
|
||||||
|
CHECK ((post_id IS NOT NULL)::integer + (comment_id IS NOT NULL)::integer = 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_profile_combined_published ON profile_combined (published DESC, id DESC);
|
||||||
|
|
||||||
|
CREATE INDEX idx_profile_combined_published_asc ON profile_combined (reverse_timestamp_sort (published) DESC, id DESC);
|
||||||
|
|
||||||
|
-- Updating the history
|
||||||
|
INSERT INTO profile_combined (published, post_id)
|
||||||
|
SELECT
|
||||||
|
published,
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
post;
|
||||||
|
|
||||||
|
INSERT INTO profile_combined (published, comment_id)
|
||||||
|
SELECT
|
||||||
|
published,
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
comment;
|
Loading…
Reference in a new issue