Implement newsreader counting
This commit is contained in:
parent
abaaddae3a
commit
9746c9912b
10
server/sql/count.sql
Normal file
10
server/sql/count.sql
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
SELECT
|
||||||
|
COUNT(*) count
|
||||||
|
FROM
|
||||||
|
post
|
||||||
|
WHERE
|
||||||
|
site = $1
|
||||||
|
AND (
|
||||||
|
NOT $2
|
||||||
|
OR NOT is_read
|
||||||
|
)
|
||||||
@ -1,4 +1,4 @@
|
|||||||
use std::{str::Utf8Error, string::FromUtf8Error};
|
use std::{convert::Infallible, str::Utf8Error, string::FromUtf8Error};
|
||||||
|
|
||||||
use mailparse::MailParseError;
|
use mailparse::MailParseError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -27,4 +27,6 @@ pub enum ServerError {
|
|||||||
FromUtf8Error(#[from] FromUtf8Error),
|
FromUtf8Error(#[from] FromUtf8Error),
|
||||||
#[error("error")]
|
#[error("error")]
|
||||||
StringError(String),
|
StringError(String),
|
||||||
|
#[error("impossible")]
|
||||||
|
InfaillibleError(#[from] Infallible),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -209,7 +209,14 @@ pub struct QueryRoot;
|
|||||||
impl QueryRoot {
|
impl QueryRoot {
|
||||||
async fn count<'ctx>(&self, ctx: &Context<'ctx>, query: String) -> Result<usize, Error> {
|
async fn count<'ctx>(&self, ctx: &Context<'ctx>, query: String) -> Result<usize, Error> {
|
||||||
let nm = ctx.data_unchecked::<Notmuch>();
|
let nm = ctx.data_unchecked::<Notmuch>();
|
||||||
Ok(nm.count(&query)?)
|
let pool = ctx.data_unchecked::<PgPool>();
|
||||||
|
|
||||||
|
// 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>(
|
async fn search<'ctx>(
|
||||||
|
|||||||
@ -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 async_graphql::connection::{self, Connection, Edge};
|
||||||
use log::info;
|
use log::info;
|
||||||
@ -20,6 +24,15 @@ pub fn is_newsreader_thread(query: &str) -> bool {
|
|||||||
query.starts_with(THREAD_PREFIX)
|
query.starts_with(THREAD_PREFIX)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn count(pool: &PgPool, query: &str) -> Result<usize, ServerError> {
|
||||||
|
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(
|
pub async fn search(
|
||||||
pool: &PgPool,
|
pool: &PgPool,
|
||||||
after: Option<String>,
|
after: Option<String>,
|
||||||
@ -28,27 +41,16 @@ pub async fn search(
|
|||||||
last: Option<i32>,
|
last: Option<i32>,
|
||||||
query: String,
|
query: String,
|
||||||
) -> Result<Connection<usize, ThreadSummary>, async_graphql::Error> {
|
) -> Result<Connection<usize, ThreadSummary>, async_graphql::Error> {
|
||||||
let mut unread_only = false;
|
let query: Query = query.parse()?;
|
||||||
let mut site = None;
|
info!("news search query {query:?}");
|
||||||
let site_prefix = format!("tag:{TAG_PREFIX}");
|
let site = query.site.expect("search has no site");
|
||||||
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:?}");
|
|
||||||
connection::query(
|
connection::query(
|
||||||
after,
|
after,
|
||||||
before,
|
before,
|
||||||
first,
|
first,
|
||||||
last,
|
last,
|
||||||
|after, before, first, last| async move {
|
|after, before, first, last| async move {
|
||||||
// TODO: handle `unread_only`
|
let rows = sqlx::query_file!("sql/threads.sql", site, query.unread_only)
|
||||||
let rows = sqlx::query_file!("sql/threads.sql", site)
|
|
||||||
.fetch_all(pool)
|
.fetch_all(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -160,3 +162,27 @@ pub async fn thread(pool: &PgPool, thread_id: String) -> Result<Thread, ServerEr
|
|||||||
}],
|
}],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Query {
|
||||||
|
unread_only: bool,
|
||||||
|
site: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Query {
|
||||||
|
type Err = Infallible;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
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 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -41,6 +41,10 @@ pub fn threadset_to_messages(thread_set: notmuch::ThreadSet) -> Result<Vec<Messa
|
|||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn count(nm: &Notmuch, query: &str) -> Result<usize, ServerError> {
|
||||||
|
Ok(nm.count(query)?)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn search(
|
pub async fn search(
|
||||||
nm: &Notmuch,
|
nm: &Notmuch,
|
||||||
after: Option<String>,
|
after: Option<String>,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user