feat: ! minor crimes ! timeline query

This commit is contained in:
nullishamy 2025-04-28 21:06:17 +01:00
parent 62931ee20b
commit d252131e0d
Signed by: amy
SSH key fingerprint: SHA256:WmV0uk6WgAQvDJlM8Ld4mFPHZo02CLXXP5VkwQ5xtyk
2 changed files with 94 additions and 68 deletions

View file

@ -39,36 +39,60 @@ pub async fn home(
config: &State<Config>, config: &State<Config>,
_user: AuthenticatedUser, _user: AuthenticatedUser,
) -> Json<Vec<TimelineStatus>> { ) -> Json<Vec<TimelineStatus>> {
let posts = sqlx::query!( #[derive(sqlx::FromRow, Debug)]
r#" struct Post {
SELECT p.id as "post_id", u.id as "user_id", p.content, p.uri as "post_uri", is_boost_source: bool,
u.username, u.display_name, u.actor_id, p.created_at, p.boosted_post_id post_id: String,
FROM post p user_id: String,
INNER JOIN user u on p.user_id = u.id post_uri: String,
ORDER BY datetime(p.created_at) DESC content: String,
created_at: String,
boosted_post_id: Option<String>,
display_name: String,
username: String
}
let posts = sqlx::query_as::<_, Post>(
r#"
WITH RECURSIVE get_home_timeline_with_boosts(
id, boosted_post_id, is_boost_source
) AS
(
SELECT p.id, p.boosted_post_id, 0 as is_boost_source
FROM post p
WHERE p.user_id IN (
SELECT u.id
FROM follow f
INNER JOIN user u ON u.actor_id = f.followed_id
WHERE f.follower_id = $1
)
UNION
SELECT p.id, p.boosted_post_id, 1 as is_boost_source
FROM post p
JOIN get_home_timeline_with_boosts tl ON tl.boosted_post_id = p.id
)
SELECT is_boost_source, p.id as "post_id", u.id as "user_id",
p.content, p.uri as "post_uri", u.username, u.display_name,
u.actor_id, p.created_at, p.boosted_post_id
FROM get_home_timeline_with_boosts
JOIN post p ON p.id = get_home_timeline_with_boosts.id
JOIN user u ON u.id = p.user_id;
"# "#
) )
.fetch_all(&mut **db) .bind("https://ferri.amy.mov/users/9b9d497b-2731-435f-a929-e609ca69dac9")
.await .fetch_all(&mut **db)
.unwrap(); .await
.unwrap();
dbg!(&posts);
let mut out = Vec::<TimelineStatus>::new(); let mut out = Vec::<TimelineStatus>::new();
for record in posts { for record in posts.iter() {
let mut boost: Option<Box<TimelineStatus>> = None; let mut boost: Option<Box<TimelineStatus>> = None;
if let Some(boosted_id) = record.boosted_post_id { if let Some(ref boosted_id) = record.boosted_post_id {
let record = sqlx::query!(
r#"
SELECT p.id as "post_id", u.id as "user_id", p.content, p.uri as "post_uri",
u.username, u.display_name, u.actor_id, p.created_at, p.boosted_post_id
FROM post p
INNER JOIN user u on p.user_id = u.id
WHERE p.id = ?1
"#, boosted_id)
.fetch_one(&mut **db)
.await
.unwrap();
let user_uri = config.user_url(&record.user_id); let user_uri = config.user_url(&record.user_id);
let record = posts.iter().find(|p| &p.post_id == boosted_id).unwrap();
boost = Some(Box::new(TimelineStatus { boost = Some(Box::new(TimelineStatus {
id: record.post_id.clone(), id: record.post_id.clone(),
created_at: record.created_at.clone(), created_at: record.created_at.clone(),
@ -111,49 +135,51 @@ pub async fn home(
}, },
})) }))
} }
let user_uri = config.user_web_url(&record.username); if !record.is_boost_source {
out.push(TimelineStatus { let user_uri = config.user_web_url(&record.username);
id: record.post_id.clone(), out.push(TimelineStatus {
created_at: record.created_at.clone(), id: record.post_id.clone(),
in_reply_to_id: None, created_at: record.created_at.clone(),
in_reply_to_account_id: None, in_reply_to_id: None,
content: record.content.clone(), in_reply_to_account_id: None,
visibility: "public".to_string(), content: record.content.clone(),
spoiler_text: "".to_string(), visibility: "public".to_string(),
sensitive: false, spoiler_text: "".to_string(),
uri: record.post_uri.clone(), sensitive: false,
url: record.post_uri.clone(), uri: record.post_uri.clone(),
replies_count: 0, url: record.post_uri.clone(),
reblogs_count: 0, replies_count: 0,
favourites_count: 0, reblogs_count: 0,
favourited: false, favourites_count: 0,
reblogged: false, favourited: false,
reblog: boost, reblogged: false,
muted: false, reblog: boost,
bookmarked: false, muted: false,
media_attachments: vec![], bookmarked: false,
account: CredentialAcount { media_attachments: vec![],
id: record.user_id.clone(), account: CredentialAcount {
username: record.username.clone(), id: record.user_id.clone(),
acct: record.username.clone(), username: record.username.clone(),
display_name: record.display_name.clone(), acct: record.username.clone(),
locked: false, display_name: record.display_name.clone(),
bot: false, locked: false,
created_at: "2025-04-10T22:12:09Z".to_string(), bot: false,
attribution_domains: vec![], created_at: "2025-04-10T22:12:09Z".to_string(),
note: "".to_string(), attribution_domains: vec![],
url: user_uri, note: "".to_string(),
avatar: "https://ferri.amy.mov/assets/pfp.png".to_string(), url: user_uri,
avatar_static: "https://ferri.amy.mov/assets/pfp.png".to_string(), avatar: "https://ferri.amy.mov/assets/pfp.png".to_string(),
header: "https://ferri.amy.mov/assets/pfp.png".to_string(), avatar_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
header_static: "https://ferri.amy.mov/assets/pfp.png".to_string(), header: "https://ferri.amy.mov/assets/pfp.png".to_string(),
followers_count: 1, header_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
following_count: 1, followers_count: 1,
statuses_count: 1, following_count: 1,
last_status_at: "2025-04-10T22:14:34Z".to_string(), statuses_count: 1,
}, last_status_at: "2025-04-10T22:14:34Z".to_string(),
}); },
});
}
} }
Json(out) Json(out)

View file

@ -1,7 +1,7 @@
CREATE TABLE IF NOT EXISTS post CREATE TABLE IF NOT EXISTS post
( (
id TEXT PRIMARY KEY NOT NULL, id TEXT PRIMARY KEY NOT NULL,
uri TEXT NOT NULL, uri TEXT NOT NULL UNIQUE,
user_id TEXT NOT NULL, user_id TEXT NOT NULL,
content TEXT NOT NULL, content TEXT NOT NULL,
created_at TEXT NOT NULL, created_at TEXT NOT NULL,