summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Reeder <vpzomtrrfrt@gmail.com>2020-12-04 18:46:29 -0700
committerColin Reeder <vpzomtrrfrt@gmail.com>2020-12-04 18:47:24 -0700
commit1b0b1e5de009d2e5638b6dc6da68153fc41c84f2 (patch)
treed2a4c70fc2d8732bcca3bfbb86222e30eeee1fbe
parentd19fd96718bb0474d0310b8bed40a28466f74ac9 (diff)
Add community search (#127)
-rw-r--r--migrations/20201205011714_community-search/down.sql4
-rw-r--r--migrations/20201205011714_community-search/up.sql9
-rw-r--r--openapi/openapi.json6
-rw-r--r--src/routes/api/communities.rs45
-rw-r--r--src/routes/api/posts.rs2
5 files changed, 54 insertions, 12 deletions
diff --git a/migrations/20201205011714_community-search/down.sql b/migrations/20201205011714_community-search/down.sql
new file mode 100644
index 0000000..1ea08f6
--- /dev/null
+++ b/migrations/20201205011714_community-search/down.sql
@@ -0,0 +1,4 @@
+BEGIN;
+ DROP INDEX community_fts;
+ DROP FUNCTION community_fts;
+COMMIT;
diff --git a/migrations/20201205011714_community-search/up.sql b/migrations/20201205011714_community-search/up.sql
new file mode 100644
index 0000000..8c20efa
--- /dev/null
+++ b/migrations/20201205011714_community-search/up.sql
@@ -0,0 +1,9 @@
+BEGIN;
+ CREATE FUNCTION community_fts(community community) RETURNS tsvector AS $$
+ BEGIN
+ RETURN setweight(to_tsvector('english', community.name), 'A') ||
+ setweight(to_tsvector('english', community.description), 'D');
+ END;
+ $$ LANGUAGE plpgsql IMMUTABLE;
+ CREATE INDEX community_fts ON community USING gin(community_fts(community));
+COMMIT;
diff --git a/openapi/openapi.json b/openapi/openapi.json
index 12c698c..8f0d2fe 100644
--- a/openapi/openapi.json
+++ b/openapi/openapi.json
@@ -472,6 +472,12 @@
"required": false,
"schema": {"type": "boolean"},
"description": "If true, will include `you_are_moderator` and `your_follow` in list. Requires login."
+ },
+ {
+ "name": "search",
+ "in": "query",
+ "required": false,
+ "schema": {"type": "string"}
}
],
"responses": {
diff --git a/src/routes/api/communities.rs b/src/routes/api/communities.rs
index aa0d80f..4392983 100644
--- a/src/routes/api/communities.rs
+++ b/src/routes/api/communities.rs
@@ -30,23 +30,46 @@ async fn route_unstable_communities_list(
ctx: Arc<crate::RouteContext>,
req: hyper::Request<hyper::Body>,
) -> Result<hyper::Response<hyper::Body>, crate::Error> {
- let query: MaybeIncludeYour = serde_urlencoded::from_str(req.uri().query().unwrap_or(""))?;
+ use std::fmt::Write;
+
+ #[derive(Deserialize)]
+ struct CommunitiesListQuery<'a> {
+ #[serde(default)]
+ search: Option<Cow<'a, str>>,
+
+ #[serde(default)]
+ include_your: bool,
+ }
+
+ let query: CommunitiesListQuery = serde_urlencoded::from_str(req.uri().query().unwrap_or(""))?;
+
+ let mut sql = String::from("SELECT id, name, local, ap_id, description");
+ let mut values: Vec<&(dyn tokio_postgres::types::ToSql + Sync)> = Vec::new();
let db = ctx.db_pool.get().await?;
- let rows = if query.include_your {
+
+ let include_your_for = if query.include_your {
let user = crate::require_login(&req, &db).await?;
- db.query(
- "SELECT id, name, local, ap_id, description, (SELECT accepted FROM community_follow WHERE community=community.id AND follower=$1), EXISTS(SELECT 1 FROM community_moderator WHERE community=community.id AND person=$1) FROM community",
- &[&user.raw()],
- ).await?
+ Some(user)
} else {
- db.query(
- "SELECT id, name, local, ap_id, description FROM community",
- &[],
- )
- .await?
+ None
};
+ if let Some(user) = &include_your_for {
+ values.push(user);
+ sql.push_str(", (SELECT accepted FROM community_follow WHERE community=community.id AND follower=$1), EXISTS(SELECT 1 FROM community_moderator WHERE community=community.id AND person=$1)");
+ }
+
+ sql.push_str(" FROM community");
+
+ if let Some(search) = &query.search {
+ values.push(search);
+ write!(sql, " WHERE community_fts(community) @@ plainto_tsquery('english', ${0}) ORDER BY ts_rank_cd(community_fts(community), plainto_tsquery('english', ${0})) DESC", values.len()).unwrap();
+ }
+
+ let sql: &str = &sql;
+ let rows = db.query(sql, &values).await?;
+
let output: Vec<_> = rows
.iter()
.map(|row| {
diff --git a/src/routes/api/posts.rs b/src/routes/api/posts.rs
index 8aacb9e..2f64c5b 100644
--- a/src/routes/api/posts.rs
+++ b/src/routes/api/posts.rs
@@ -183,7 +183,7 @@ async fn route_unstable_posts_list(
PostsListSortType::Normal(ty) => sql.push_str(ty.post_sort_sql()),
PostsListSortType::Extra(PostsListExtraSortType::Relevant) => {
if let Some(search_value_idx) = search_value_idx {
- write!(sql, "ts_rank_cd(to_tsvector('english', title || ' ' || COALESCE(content_text, content_markdown, content_html, '')), plainto_tsquery('english', ${}))", search_value_idx).unwrap();
+ write!(sql, "ts_rank_cd(to_tsvector('english', title || ' ' || COALESCE(content_text, content_markdown, content_html, '')), plainto_tsquery('english', ${})) DESC", search_value_idx).unwrap();
} else {
return Err(crate::Error::UserError(crate::simple_response(
hyper::StatusCode::BAD_REQUEST,