From 9746c9912b6f1d3b97e5a71a9f4ee24d26e1590a Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Sun, 21 Jul 2024 15:13:09 -0700 Subject: [PATCH] Implement newsreader counting --- server/sql/count.sql | 10 +++++++ server/src/error.rs | 4 ++- server/src/graphql.rs | 9 ++++++- server/src/newsreader.rs | 58 +++++++++++++++++++++++++++++----------- server/src/nm.rs | 4 +++ 5 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 server/sql/count.sql diff --git a/server/sql/count.sql b/server/sql/count.sql new file mode 100644 index 0000000..3c01d75 --- /dev/null +++ b/server/sql/count.sql @@ -0,0 +1,10 @@ +SELECT + COUNT(*) count +FROM + post +WHERE + site = $1 + AND ( + NOT $2 + OR NOT is_read + ) diff --git a/server/src/error.rs b/server/src/error.rs index b2f6b1b..869e901 100644 --- a/server/src/error.rs +++ b/server/src/error.rs @@ -1,4 +1,4 @@ -use std::{str::Utf8Error, string::FromUtf8Error}; +use std::{convert::Infallible, str::Utf8Error, string::FromUtf8Error}; use mailparse::MailParseError; use thiserror::Error; @@ -27,4 +27,6 @@ pub enum ServerError { FromUtf8Error(#[from] FromUtf8Error), #[error("error")] StringError(String), + #[error("impossible")] + InfaillibleError(#[from] Infallible), } diff --git a/server/src/graphql.rs b/server/src/graphql.rs index 9b8e97d..d293d29 100644 --- a/server/src/graphql.rs +++ b/server/src/graphql.rs @@ -209,7 +209,14 @@ pub struct QueryRoot; impl QueryRoot { async fn count<'ctx>(&self, ctx: &Context<'ctx>, query: String) -> Result { let nm = ctx.data_unchecked::(); - Ok(nm.count(&query)?) + let pool = ctx.data_unchecked::(); + + // TODO: make this search both copra and merge results + if newsreader::is_newsreader_search(&query) { + Ok(newsreader::count(pool, &query).await?) + } else { + Ok(nm::count(nm, &query).await?) + } } async fn search<'ctx>( diff --git a/server/src/newsreader.rs b/server/src/newsreader.rs index cec7239..8c268a5 100644 --- a/server/src/newsreader.rs +++ b/server/src/newsreader.rs @@ -1,4 +1,8 @@ -use std::hash::{DefaultHasher, Hash, Hasher}; +use std::{ + convert::Infallible, + hash::{DefaultHasher, Hash, Hasher}, + str::FromStr, +}; use async_graphql::connection::{self, Connection, Edge}; use log::info; @@ -20,6 +24,15 @@ pub fn is_newsreader_thread(query: &str) -> bool { query.starts_with(THREAD_PREFIX) } +pub async fn count(pool: &PgPool, query: &str) -> Result { + let query: Query = query.parse()?; + let site = query.site.expect("search has no site"); + let row = sqlx::query_file!("sql/count.sql", site, query.unread_only) + .fetch_one(pool) + .await?; + Ok(row.count.unwrap_or(0).try_into().unwrap_or(0)) +} + pub async fn search( pool: &PgPool, after: Option, @@ -28,27 +41,16 @@ pub async fn search( last: Option, query: String, ) -> Result, async_graphql::Error> { - let mut unread_only = false; - let mut site = None; - let site_prefix = format!("tag:{TAG_PREFIX}"); - for word in query.split_whitespace() { - if word == "is:unread" { - unread_only = true - }; - if word.starts_with(&site_prefix) { - site = Some(word[site_prefix.len()..].to_string()) - } - } - let site = site.expect("search has no site"); - info!("news search unread_only {unread_only} site {site:?}"); + let query: Query = query.parse()?; + info!("news search query {query:?}"); + let site = query.site.expect("search has no site"); connection::query( after, before, first, last, |after, before, first, last| async move { - // TODO: handle `unread_only` - let rows = sqlx::query_file!("sql/threads.sql", site) + let rows = sqlx::query_file!("sql/threads.sql", site, query.unread_only) .fetch_all(pool) .await?; @@ -160,3 +162,27 @@ pub async fn thread(pool: &PgPool, thread_id: String) -> Result, +} + +impl FromStr for Query { + type Err = Infallible; + fn from_str(s: &str) -> Result { + let mut unread_only = false; + let mut site = None; + let site_prefix = format!("tag:{TAG_PREFIX}"); + for word in s.split_whitespace() { + if word == "is:unread" { + unread_only = true + }; + if word.starts_with(&site_prefix) { + site = Some(word[site_prefix.len()..].to_string()) + } + } + Ok(Query { unread_only, site }) + } +} diff --git a/server/src/nm.rs b/server/src/nm.rs index f579ff5..72cc6ca 100644 --- a/server/src/nm.rs +++ b/server/src/nm.rs @@ -41,6 +41,10 @@ pub fn threadset_to_messages(thread_set: notmuch::ThreadSet) -> Result Result { + Ok(nm.count(query)?) +} + pub async fn search( nm: &Notmuch, after: Option,