about summary refs log tree commit diff
path: root/src/db.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/db.rs')
-rw-r--r--src/db.rs41
1 files changed, 40 insertions, 1 deletions
diff --git a/src/db.rs b/src/db.rs
index 5a66fbb0fc..416e3fdd0f 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -17,7 +17,8 @@
 //! This module implements the database connection actor.
 
 use actix::prelude::*;
-use diesel;
+use diesel::{self, sql_query};
+use diesel::sql_types::Text;
 use diesel::prelude::*;
 use diesel::r2d2::{Pool, ConnectionManager};
 use models::*;
@@ -138,3 +139,41 @@ impl Handler<CreatePost> for DbExecutor {
            .get_result(&conn)?)
     }
 }
+
+/// Message used to search for posts
+#[derive(Deserialize)]
+pub struct SearchPosts { pub query: String }
+
+impl Message for SearchPosts {
+    type Result = Result<Vec<SearchResult>>;
+}
+
+/// Raw PostgreSQL query used to perform full-text search on posts
+/// with a supplied phrase. For now, the query language is hardcoded
+/// to English and only "plain" queries (i.e. no searches for exact
+/// matches or more advanced query syntax) are supported.
+const SEARCH_QUERY: &'static str = r#"
+WITH search_query (query) AS (VALUES (plainto_tsquery('english', $1)))
+SELECT post_id,
+       thread_id,
+       author,
+       title,
+       ts_headline('english', body, query) AS headline
+  FROM search_index, search_query
+  WHERE document @@ query
+  ORDER BY ts_rank(document, query) DESC
+"#;
+
+impl Handler<SearchPosts> for DbExecutor {
+    type Result = <SearchPosts as Message>::Result;
+
+    fn handle(&mut self, msg: SearchPosts, _: &mut Self::Context) -> Self::Result {
+        let conn = self.0.get()?;
+
+        let search_results = sql_query(SEARCH_QUERY)
+            .bind::<Text, _>(msg.query)
+            .get_results::<SearchResult>(&conn)?;
+
+        Ok(search_results)
+    }
+}