~vpzom/lotide

9bb065b5da31d4b1b5d212a1ca7941717f17ace5 — Colin Reeder 14 days ago 0acc624
Include replies_count_total in post lists (#123)
M openapi/openapi.json => openapi/openapi.json +14 -2
@@ 100,7 100,7 @@
					}
				}
			},
			"PostListPost": {
			"SomePostInfo": {
				"type": "object",
				"required": ["id", "title", "created", "community", "score"],
				"properties": {


@@ 134,6 134,18 @@
					"your_vote": {"$ref": "#/components/schemas/YourVote"}
				}
			},
			"PostListPost": {
				"allOf": [
					{"$ref": "#/components/schemas/SomePostInfo"},
					{
						"type": "object",
						"required": ["replies_count_total"],
						"properties": {
							"replies_count_total": {"type": "integer"}
						}
					}
				]
			},
			"PostCommentInfo": {
				"type": "object",
				"required": ["id", "content_text", "content_html", "author", "created", "deleted", "replies", "has_replies", "attachments", "local"],


@@ 1140,7 1152,7 @@
						"content": {
							"application/json": {
								"schema": {
									"allOf": [{"$ref": "#/components/schemas/PostListPost"}],
									"allOf": [{"$ref": "#/components/schemas/SomePostInfo"}],
									"type": "object",
									"required": ["approved", "local", "replies"],
									"properties": {

M src/routes/api/communities.rs => src/routes/api/communities.rs +3 -2
@@ 602,7 602,7 @@ async fn route_unstable_communities_posts_list(

    let mut values: Vec<&(dyn tokio_postgres::types::ToSql + Sync)> = vec![&community_id, &limit];
    let sql: &str = &format!(
        "SELECT post.id, post.author, post.href, post.content_text, post.title, post.created, post.content_html, person.username, person.local, person.ap_id, person.avatar, (SELECT COUNT(*) FROM post_like WHERE post_like.post = post.id){} FROM post LEFT OUTER JOIN person ON (person.id = post.author) WHERE post.community = $1 AND post.approved=TRUE AND post.deleted=FALSE ORDER BY {} LIMIT $2",
        "SELECT post.id, post.author, post.href, post.content_text, post.title, post.created, post.content_html, person.username, person.local, person.ap_id, person.avatar, (SELECT COUNT(*) FROM post_like WHERE post_like.post = post.id), (SELECT COUNT(*) FROM reply WHERE reply.post = post.id){} FROM post LEFT OUTER JOIN person ON (person.id = post.author) WHERE post.community = $1 AND post.approved=TRUE AND post.deleted=FALSE ORDER BY {} LIMIT $2",
        if let Some(user) = &include_your_for {
            values.push(user);
            ", EXISTS(SELECT 1 FROM post_like WHERE post=post.id AND person=$3)"


@@ 658,9 658,10 @@ async fn route_unstable_communities_posts_list(
                author: author.as_ref(),
                created: &created.to_rfc3339(),
                community: &community,
                replies_count_total: Some(row.get(12)),
                score: row.get(11),
                your_vote: if include_your_for.is_some() {
                    Some(if row.get(12) {
                    Some(if row.get(13) {
                        Some(crate::Empty {})
                    } else {
                        None

M src/routes/api/mod.rs => src/routes/api/mod.rs +18 -1
@@ 111,6 111,8 @@ struct RespPostListPost<'a> {
    author: Option<&'a RespMinimalAuthorInfo<'a>>,
    created: &'a str,
    community: &'a RespMinimalCommunityInfo<'a>,
    #[serde(skip_serializing_if = "Option::is_none")]
    replies_count_total: Option<i64>,
    score: i64,
    #[serde(skip_serializing_if = "Option::is_none")]
    your_vote: Option<Option<crate::Empty>>,


@@ 156,6 158,8 @@ enum RespThingInfo<'a> {
        title: &'a str,
        created: String,
        community: RespMinimalCommunityInfo<'a>,
        replies_count_total: i64,
        score: i64,
    },
    #[serde(rename = "comment")]
    Comment {


@@ 758,6 762,18 @@ async fn route_unstable_misc_render_markdown(
    crate::json_response(&serde_json::json!({ "content_html": html }))
}

fn common_posts_list_query(include_your_idx: Option<usize>) -> Cow<'static, str> {
    const BASE: &str = "post.id, post.author, post.href, post.content_text, post.title, post.created, post.content_html, community.id, community.name, community.local, community.ap_id, person.username, person.local, person.ap_id, person.avatar, (SELECT COUNT(*) FROM post_like WHERE post_like.post = post.id), (SELECT COUNT(*) FROM reply WHERE reply.post = post.id)";
    match include_your_idx {
        None => BASE.into(),
        Some(idx) => format!(
            "{}, EXISTS(SELECT 1 FROM post_like WHERE post=post.id AND person=${})",
            BASE, idx
        )
        .into(),
    }
}

async fn handle_common_posts_list(
    stream: impl futures::stream::TryStream<Ok = tokio_postgres::Row, Error = tokio_postgres::Error>
        + Send,


@@ 824,8 840,9 @@ async fn handle_common_posts_list(
                created: &created.to_rfc3339(),
                community: &community,
                score: row.get(15),
                replies_count_total: Some(row.get(16)),
                your_vote: if include_your {
                    Some(if row.get(16) {
                    Some(if row.get(17) {
                        Some(crate::Empty {})
                    } else {
                        None

M src/routes/api/posts.rs => src/routes/api/posts.rs +11 -7
@@ 125,14 125,17 @@ async fn route_unstable_posts_list(

    let mut values: Vec<&(dyn tokio_postgres::types::ToSql + Sync)> = vec![&limit];

    let sql: &str = &format!(
        "SELECT post.id, post.author, post.href, post.content_text, post.title, post.created, post.content_html, community.id, community.name, community.local, community.ap_id, person.username, person.local, person.ap_id, person.avatar, (SELECT COUNT(*) FROM post_like WHERE post_like.post = post.id){} FROM community, post LEFT OUTER JOIN person ON (person.id = post.author) WHERE post.community = community.id AND deleted=FALSE ORDER BY hot_rank((SELECT COUNT(*) FROM post_like WHERE post = post.id AND person != post.author), post.created) DESC LIMIT $1",
        if let Some(user) = &include_your_for {
    let include_your_idx = match &include_your_for {
        None => None,
        Some(user) => {
            values.push(user);
            ", EXISTS(SELECT 1 FROM post_like WHERE post=post.id AND person=$2)"
        } else {
            ""
        },
            Some(values.len())
        }
    };

    let sql: &str = &format!(
        "SELECT {} FROM community, post LEFT OUTER JOIN person ON (person.id = post.author) WHERE post.community = community.id AND deleted=FALSE ORDER BY hot_rank((SELECT COUNT(*) FROM post_like WHERE post = post.id AND person != post.author), post.created) DESC LIMIT $1",
        super::common_posts_list_query(include_your_idx),
    );

    let stream = crate::query_stream(&db, sql, &values).await?;


@@ 380,6 383,7 @@ async fn route_unstable_posts_get(
                author: author.as_ref(),
                created: &created.to_rfc3339(),
                community: &community,
                replies_count_total: None,
                score: row.get(13),
                your_vote,
            };

M src/routes/api/users.rs => src/routes/api/users.rs +8 -6
@@ 1,11 1,11 @@
use super::{
    handle_common_posts_list, MaybeIncludeYour, RespAvatarInfo, RespLoginUserInfo,
    RespMinimalAuthorInfo, RespMinimalCommentInfo, RespMinimalCommunityInfo, RespMinimalPostInfo,
    RespThingInfo,
    MaybeIncludeYour, RespAvatarInfo, RespLoginUserInfo, RespMinimalAuthorInfo,
    RespMinimalCommentInfo, RespMinimalCommunityInfo, RespMinimalPostInfo, RespThingInfo,
};
use crate::{CommentLocalID, CommunityLocalID, PostLocalID, UserLocalID};
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;
use std::ops::Deref;
use std::sync::Arc;

struct MeOrLocalAndAdminResult {


@@ 357,11 357,11 @@ async fn route_unstable_users_following_posts_list(
    let values: &[&(dyn tokio_postgres::types::ToSql + Sync)] = &[&user, &limit];

    let stream = db.query_raw(
        "SELECT post.id, post.author, post.href, post.content_text, post.title, post.created, post.content_html, community.id, community.name, community.local, community.ap_id, person.username, person.local, person.ap_id, person.avatar, (SELECT COUNT(*) FROM post_like WHERE post_like.post = post.id), EXISTS(SELECT 1 FROM post_like WHERE post = post.id AND person = $1) FROM community, post LEFT OUTER JOIN person ON (person.id = post.author) WHERE post.community = community.id AND post.approved AND post.deleted=FALSE AND community.id IN (SELECT community FROM community_follow WHERE follower=$1 AND accepted) ORDER BY hot_rank((SELECT COUNT(*) FROM post_like WHERE post = post.id AND person != post.author), post.created) DESC LIMIT $2",
        format!("SELECT {} FROM community, post LEFT OUTER JOIN person ON (person.id = post.author) WHERE post.community = community.id AND post.approved AND post.deleted=FALSE AND community.id IN (SELECT community FROM community_follow WHERE follower=$1 AND accepted) ORDER BY hot_rank((SELECT COUNT(*) FROM post_like WHERE post = post.id AND person != post.author), post.created) DESC LIMIT $2", super::common_posts_list_query(Some(1))).deref(),
        values.iter().map(|s| *s as _)
    ).await?;

    let posts = handle_common_posts_list(stream, &ctx, true).await?;
    let posts = super::handle_common_posts_list(stream, &ctx, true).await?;

    crate::json_response(&posts)
}


@@ 608,7 608,7 @@ async fn route_unstable_users_things_list(
    let limit: i64 = 30;

    let rows = db.query(
        "(SELECT TRUE, post.id, post.href, post.title, post.created, community.id, community.name, community.local, community.ap_id FROM post, community WHERE post.community = community.id AND post.author = $1 AND NOT post.deleted) UNION ALL (SELECT FALSE, reply.id, reply.content_text, reply.content_html, reply.created, post.id, post.title, NULL, NULL FROM reply, post WHERE post.id = reply.post AND reply.author = $1 AND NOT reply.deleted) ORDER BY created DESC LIMIT $2",
        "(SELECT TRUE, post.id, post.href, post.title, post.created, community.id, community.name, community.local, community.ap_id, (SELECT COUNT(*) FROM post_like WHERE post_like.post = post.id), (SELECT COUNT(*) FROM reply WHERE reply.post = post.id) FROM post, community WHERE post.community = community.id AND post.author = $1 AND NOT post.deleted) UNION ALL (SELECT FALSE, reply.id, reply.content_text, reply.content_html, reply.created, post.id, post.title, NULL, NULL, NULL, NULL FROM reply, post WHERE post.id = reply.post AND reply.author = $1 AND NOT reply.deleted) ORDER BY created DESC LIMIT $2",
        &[&user_id, &limit],
    )
        .await?;


@@ 641,6 641,8 @@ async fn route_unstable_users_things_list(
                        ),
                        remote_url: community_ap_id,
                    },
                    replies_count_total: row.get(10),
                    score: row.get(9),
                }
            } else {
                RespThingInfo::Comment {