Create post_link table to store links between posts

This commit is contained in:
silverpill 2022-08-21 21:15:30 +00:00
parent fcf7db97cb
commit d9def75b32
8 changed files with 122 additions and 19 deletions

View file

@ -0,0 +1,5 @@
CREATE TABLE post_link (
source_id UUID NOT NULL REFERENCES post (id) ON DELETE CASCADE,
target_id UUID NOT NULL REFERENCES post (id) ON DELETE CASCADE,
PRIMARY KEY (source_id, target_id)
);

View file

@ -112,6 +112,12 @@ CREATE TABLE post_tag (
PRIMARY KEY (post_id, tag_id)
);
CREATE TABLE post_link (
source_id UUID NOT NULL REFERENCES post (id) ON DELETE CASCADE,
target_id UUID NOT NULL REFERENCES post (id) ON DELETE CASCADE,
PRIMARY KEY (source_id, target_id)
);
CREATE TABLE notification (
id SERIAL PRIMARY KEY,
sender_id UUID NOT NULL REFERENCES actor_profile (id) ON DELETE CASCADE,

View file

@ -321,6 +321,7 @@ pub async fn handle_note(
attachments: attachments,
mentions: mentions,
tags: tags,
links: vec![],
object_id: Some(object.id),
created_at: object.published,
};

View file

@ -163,6 +163,7 @@ impl TryFrom<StatusData> for PostCreateData {
attachments: value.media_ids.unwrap_or(vec![]),
mentions: value.mentions.unwrap_or(vec![]),
tags: vec![],
links: vec![],
object_id: None,
created_at: None,
};

View file

@ -7,6 +7,7 @@ use crate::errors::DatabaseError;
use crate::models::posts::helpers::add_user_actions;
use crate::models::posts::queries::{
RELATED_ATTACHMENTS,
RELATED_LINKS,
RELATED_MENTIONS,
RELATED_TAGS,
};
@ -127,7 +128,8 @@ pub async fn get_notifications(
notification, sender, post, post_author,
{related_attachments},
{related_mentions},
{related_tags}
{related_tags},
{related_links}
FROM notification
JOIN actor_profile AS sender
ON notification.sender_id = sender.id
@ -144,6 +146,7 @@ pub async fn get_notifications(
related_attachments=RELATED_ATTACHMENTS,
related_mentions=RELATED_MENTIONS,
related_tags=RELATED_TAGS,
related_links=RELATED_LINKS,
);
let rows = db_client.query(
statement.as_str(),

View file

@ -97,12 +97,14 @@ impl TryFrom<&Row> for Notification {
let db_attachments: Vec<DbMediaAttachment> = row.try_get("attachments")?;
let db_mentions: Vec<DbActorProfile> = row.try_get("mentions")?;
let db_tags: Vec<String> = row.try_get("tags")?;
let db_links: Vec<Uuid> = row.try_get("links")?;
let post = Post::new(
db_post,
db_post_author,
db_attachments,
db_mentions,
db_tags,
db_links,
)?;
Some(post)
},

View file

@ -96,7 +96,7 @@ pub async fn create_post(
if attachments_rows.len() != data.attachments.len() {
// Some attachments were not found
return Err(DatabaseError::NotFound("attachment"));
}
};
let db_attachments: Vec<DbMediaAttachment> = attachments_rows.iter()
.map(|row| row.try_get("media_attachment"))
.collect::<Result<_, _>>()?;
@ -104,7 +104,7 @@ pub async fn create_post(
let mentions_rows = transaction.query(
"
INSERT INTO mention (post_id, profile_id)
SELECT $1, unnest($2::uuid[])
SELECT $1, actor_profile.id FROM actor_profile WHERE id = ANY($2)
RETURNING (
SELECT actor_profile FROM actor_profile
WHERE actor_profile.id = profile_id
@ -142,6 +142,21 @@ pub async fn create_post(
let db_tags: Vec<String> = tags_rows.iter()
.map(|row| row.try_get("tag_name"))
.collect::<Result<_, _>>()?;
// Create links
let links_rows = transaction.query(
"
INSERT INTO post_link (source_id, target_id)
SELECT $1, post.id FROM post WHERE id = ANY($2)
RETURNING target_id
",
&[&db_post.id, &data.links],
).await?;
if links_rows.len() != data.links.len() {
return Err(DatabaseError::NotFound("post"));
};
let db_links: Vec<Uuid> = links_rows.iter()
.map(|row| row.try_get("target_id"))
.collect::<Result<_, _>>()?;
// Update counters
let author = update_post_count(&transaction, &db_post.author_id, 1).await?;
let mut notified_users = vec![];
@ -194,7 +209,14 @@ pub async fn create_post(
};
transaction.commit().await?;
let post = Post::new(db_post, author, db_attachments, db_mentions, db_tags)?;
let post = Post::new(
db_post,
author,
db_attachments,
db_mentions,
db_tags,
db_links,
)?;
Ok(post)
}
@ -219,6 +241,12 @@ pub const RELATED_TAGS: &str =
WHERE post_tag.post_id = post.id
) AS tags";
pub const RELATED_LINKS: &str =
"ARRAY(
SELECT post_link.target_id FROM post_link
WHERE post_link.source_id = post.id
) AS links";
fn build_visibility_filter() -> String {
format!(
"(
@ -266,7 +294,8 @@ pub async fn get_home_timeline(
post, actor_profile,
{related_attachments},
{related_mentions},
{related_tags}
{related_tags},
{related_links}
FROM post
JOIN actor_profile ON post.author_id = actor_profile.id
WHERE
@ -331,6 +360,7 @@ pub async fn get_home_timeline(
related_attachments=RELATED_ATTACHMENTS,
related_mentions=RELATED_MENTIONS,
related_tags=RELATED_TAGS,
related_links=RELATED_LINKS,
relationship_follow=i16::from(&RelationshipType::Follow),
relationship_subscription=i16::from(&RelationshipType::Subscription),
relationship_hide_reposts=i16::from(&RelationshipType::HideReposts),
@ -362,7 +392,8 @@ pub async fn get_local_timeline(
post, actor_profile,
{related_attachments},
{related_mentions},
{related_tags}
{related_tags},
{related_links}
FROM post
JOIN actor_profile ON post.author_id = actor_profile.id
WHERE
@ -375,6 +406,7 @@ pub async fn get_local_timeline(
related_attachments=RELATED_ATTACHMENTS,
related_mentions=RELATED_MENTIONS,
related_tags=RELATED_TAGS,
related_links=RELATED_LINKS,
visibility_public=i16::from(&Visibility::Public),
);
let query = query!(
@ -400,7 +432,8 @@ pub async fn get_posts(
post, actor_profile,
{related_attachments},
{related_mentions},
{related_tags}
{related_tags},
{related_links}
FROM post
JOIN actor_profile ON post.author_id = actor_profile.id
WHERE post.id = ANY($1)
@ -408,6 +441,7 @@ pub async fn get_posts(
related_attachments=RELATED_ATTACHMENTS,
related_mentions=RELATED_MENTIONS,
related_tags=RELATED_TAGS,
related_links=RELATED_LINKS,
);
let rows = db_client.query(
statement.as_str(),
@ -446,7 +480,8 @@ pub async fn get_posts_by_author(
post, actor_profile,
{related_attachments},
{related_mentions},
{related_tags}
{related_tags},
{related_links}
FROM post
JOIN actor_profile ON post.author_id = actor_profile.id
WHERE {condition}
@ -456,6 +491,7 @@ pub async fn get_posts_by_author(
related_attachments=RELATED_ATTACHMENTS,
related_mentions=RELATED_MENTIONS,
related_tags=RELATED_TAGS,
related_links=RELATED_LINKS,
condition=condition,
);
let query = query!(
@ -486,7 +522,8 @@ pub async fn get_posts_by_tag(
post, actor_profile,
{related_attachments},
{related_mentions},
{related_tags}
{related_tags},
{related_links}
FROM post
JOIN actor_profile ON post.author_id = actor_profile.id
WHERE
@ -502,6 +539,7 @@ pub async fn get_posts_by_tag(
related_attachments=RELATED_ATTACHMENTS,
related_mentions=RELATED_MENTIONS,
related_tags=RELATED_TAGS,
related_links=RELATED_LINKS,
visibility_filter=build_visibility_filter(),
);
let query = query!(
@ -528,7 +566,8 @@ pub async fn get_post_by_id(
post, actor_profile,
{related_attachments},
{related_mentions},
{related_tags}
{related_tags},
{related_links}
FROM post
JOIN actor_profile ON post.author_id = actor_profile.id
WHERE post.id = $1
@ -536,6 +575,7 @@ pub async fn get_post_by_id(
related_attachments=RELATED_ATTACHMENTS,
related_mentions=RELATED_MENTIONS,
related_tags=RELATED_TAGS,
related_links=RELATED_LINKS,
);
let maybe_row = db_client.query_opt(
statement.as_str(),
@ -579,7 +619,8 @@ pub async fn get_thread(
post, actor_profile,
{related_attachments},
{related_mentions},
{related_tags}
{related_tags},
{related_links}
FROM post
JOIN thread ON post.id = thread.id
JOIN actor_profile ON post.author_id = actor_profile.id
@ -589,6 +630,7 @@ pub async fn get_thread(
related_attachments=RELATED_ATTACHMENTS,
related_mentions=RELATED_MENTIONS,
related_tags=RELATED_TAGS,
related_links=RELATED_LINKS,
visibility_filter=build_visibility_filter(),
);
let query = query!(
@ -616,7 +658,8 @@ pub async fn get_post_by_object_id(
post, actor_profile,
{related_attachments},
{related_mentions},
{related_tags}
{related_tags},
{related_links}
FROM post
JOIN actor_profile ON post.author_id = actor_profile.id
WHERE post.object_id = $1
@ -624,6 +667,7 @@ pub async fn get_post_by_object_id(
related_attachments=RELATED_ATTACHMENTS,
related_mentions=RELATED_MENTIONS,
related_tags=RELATED_TAGS,
related_links=RELATED_LINKS,
);
let maybe_row = db_client.query_opt(
statement.as_str(),
@ -644,7 +688,8 @@ pub async fn get_post_by_ipfs_cid(
post, actor_profile,
{related_attachments},
{related_mentions},
{related_tags}
{related_tags},
{related_links}
FROM post
JOIN actor_profile ON post.author_id = actor_profile.id
WHERE post.ipfs_cid = $1
@ -652,6 +697,7 @@ pub async fn get_post_by_ipfs_cid(
related_attachments=RELATED_ATTACHMENTS,
related_mentions=RELATED_MENTIONS,
related_tags=RELATED_TAGS,
related_links=RELATED_LINKS,
);
let result = db_client.query_opt(
statement.as_str(),
@ -1086,21 +1132,44 @@ mod tests {
#[serial]
async fn test_create_post() {
let db_client = &mut create_test_database().await;
let profile_data = ProfileCreateData {
let author_data = ProfileCreateData {
username: "test".to_string(),
..Default::default()
};
let profile = create_profile(db_client, profile_data).await.unwrap();
let author = create_profile(db_client, author_data).await.unwrap();
let post_data = PostCreateData {
content: "test post".to_string(),
..Default::default()
};
let post = create_post(db_client, &profile.id, post_data).await.unwrap();
let post = create_post(db_client, &author.id, post_data).await.unwrap();
assert_eq!(post.content, "test post");
assert_eq!(post.author.id, profile.id);
assert_eq!(post.author.id, author.id);
assert_eq!(post.attachments.is_empty(), true);
assert_eq!(post.mentions.is_empty(), true);
assert_eq!(post.tags.is_empty(), true);
assert_eq!(post.links.is_empty(), true);
assert_eq!(post.updated_at, None);
}
#[tokio::test]
#[serial]
async fn test_create_post_with_link() {
let db_client = &mut create_test_database().await;
let author_data = ProfileCreateData {
username: "test".to_string(),
..Default::default()
};
let author = create_profile(db_client, author_data).await.unwrap();
let post_data_1 = PostCreateData::default();
let post_1 = create_post(db_client, &author.id, post_data_1).await.unwrap();
let post_data_2 = PostCreateData {
links: vec![post_1.id],
..Default::default()
};
let post_2 = create_post(db_client, &author.id, post_data_2).await.unwrap();
assert_eq!(post_2.links, vec![post_1.id]);
}
#[tokio::test]
#[serial]
async fn test_update_post() {

View file

@ -94,6 +94,7 @@ pub struct Post {
pub attachments: Vec<DbMediaAttachment>,
pub mentions: Vec<DbActorProfile>,
pub tags: Vec<String>,
pub links: Vec<Uuid>,
pub object_id: Option<String>,
pub ipfs_cid: Option<String>,
pub token_id: Option<i32>,
@ -115,6 +116,7 @@ impl Post {
db_attachments: Vec<DbMediaAttachment>,
db_mentions: Vec<DbActorProfile>,
db_tags: Vec<String>,
db_links: Vec<Uuid>,
) -> Result<Self, ConversionError> {
// Consistency checks
if db_post.author_id != db_author.id {
@ -131,7 +133,8 @@ impl Post {
db_post.token_tx_id.is_some() ||
!db_attachments.is_empty() ||
!db_mentions.is_empty() ||
!db_tags.is_empty()
!db_tags.is_empty() ||
!db_links.is_empty()
) {
return Err(ConversionError);
};
@ -148,6 +151,7 @@ impl Post {
attachments: db_attachments,
mentions: db_mentions,
tags: db_tags,
links: db_links,
object_id: db_post.object_id,
ipfs_cid: db_post.ipfs_cid,
token_id: db_post.token_id,
@ -189,6 +193,7 @@ impl Default for Post {
attachments: vec![],
mentions: vec![],
tags: vec![],
links: vec![],
object_id: None,
ipfs_cid: None,
token_id: None,
@ -212,7 +217,15 @@ impl TryFrom<&Row> for Post {
let db_attachments: Vec<DbMediaAttachment> = row.try_get("attachments")?;
let db_mentions: Vec<DbActorProfile> = row.try_get("mentions")?;
let db_tags: Vec<String> = row.try_get("tags")?;
let post = Self::new(db_post, db_profile, db_attachments, db_mentions, db_tags)?;
let db_links: Vec<Uuid> = row.try_get("links")?;
let post = Self::new(
db_post,
db_profile,
db_attachments,
db_mentions,
db_tags,
db_links,
)?;
Ok(post)
}
}
@ -226,6 +239,7 @@ pub struct PostCreateData {
pub attachments: Vec<Uuid>,
pub mentions: Vec<Uuid>,
pub tags: Vec<String>,
pub links: Vec<Uuid>,
pub object_id: Option<String>,
pub created_at: Option<DateTime<Utc>>,
}
@ -267,6 +281,7 @@ mod tests {
attachments: vec![],
mentions: vec![],
tags: vec![],
links: vec![],
object_id: None,
created_at: None,
};
@ -283,6 +298,7 @@ mod tests {
attachments: vec![],
mentions: vec![],
tags: vec![],
links: vec![],
object_id: None,
created_at: None,
};