And graphql search with pagination.
This commit is contained in:
parent
f52a76dba3
commit
a7b172099b
@ -1,17 +1,8 @@
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
use std::{error::Error, io::Cursor, str::FromStr};
|
||||
|
||||
use std::{
|
||||
error::Error,
|
||||
hash::{DefaultHasher, Hash, Hasher},
|
||||
io::Cursor,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use async_graphql::{
|
||||
http::GraphiQLSource, Context, EmptyMutation, EmptySubscription, FieldResult, Object, Schema,
|
||||
SimpleObject,
|
||||
};
|
||||
use async_graphql::{http::GraphiQLSource, EmptyMutation, EmptySubscription, Schema};
|
||||
use async_graphql_rocket::{GraphQLQuery, GraphQLRequest, GraphQLResponse};
|
||||
use glog::Flags;
|
||||
use notmuch::{Notmuch, NotmuchError, ThreadSet};
|
||||
@ -23,7 +14,11 @@ use rocket::{
|
||||
Response, State,
|
||||
};
|
||||
use rocket_cors::{AllowedHeaders, AllowedOrigins};
|
||||
use server::{error::ServerError, nm::threadset_to_messages};
|
||||
use server::{
|
||||
error::ServerError,
|
||||
graphql::{GraphqlSchema, QueryRoot},
|
||||
nm::threadset_to_messages,
|
||||
};
|
||||
use shared::Message;
|
||||
|
||||
#[get("/refresh")]
|
||||
@ -148,38 +143,6 @@ async fn graphql_request(
|
||||
request.execute(schema.inner()).await
|
||||
}
|
||||
|
||||
pub struct QueryRoot;
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
struct Tag {
|
||||
name: String,
|
||||
fg_color: String,
|
||||
bg_color: String,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl QueryRoot {
|
||||
async fn tags<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Vec<Tag>> {
|
||||
let nm = ctx.data_unchecked::<Notmuch>();
|
||||
Ok(nm
|
||||
.tags()?
|
||||
.into_iter()
|
||||
.map(|tag| {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
tag.hash(&mut hasher);
|
||||
let hex = format!("#{:06x}", hasher.finish() % (1 << 24));
|
||||
Tag {
|
||||
name: tag,
|
||||
fg_color: "white".to_string(),
|
||||
bg_color: hex,
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
pub type GraphqlSchema = Schema<QueryRoot, EmptyMutation, EmptySubscription>;
|
||||
|
||||
#[rocket::main]
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
glog::new()
|
||||
|
||||
138
server/src/graphql.rs
Normal file
138
server/src/graphql.rs
Normal file
@ -0,0 +1,138 @@
|
||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||
|
||||
use async_graphql::{
|
||||
connection::{self, Connection, Edge},
|
||||
Context, EmptyMutation, EmptySubscription, Error, FieldResult, Object, Schema, SimpleObject,
|
||||
};
|
||||
use log::info;
|
||||
use notmuch::Notmuch;
|
||||
|
||||
pub struct QueryRoot;
|
||||
|
||||
/// # Number of seconds since the Epoch
|
||||
pub type UnixTime = isize;
|
||||
|
||||
/// # Thread ID, sans "thread:"
|
||||
pub type ThreadId = String;
|
||||
|
||||
#[derive(Debug, SimpleObject)]
|
||||
pub struct ThreadSummary {
|
||||
pub thread: ThreadId,
|
||||
pub timestamp: UnixTime,
|
||||
/// user-friendly timestamp
|
||||
pub date_relative: String,
|
||||
/// number of matched messages
|
||||
pub matched: isize,
|
||||
/// total messages in thread
|
||||
pub total: isize,
|
||||
/// comma-separated names with | between matched and unmatched
|
||||
pub authors: String,
|
||||
pub subject: String,
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
struct Tag {
|
||||
name: String,
|
||||
fg_color: String,
|
||||
bg_color: String,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl QueryRoot {
|
||||
async fn search<'ctx>(
|
||||
&self,
|
||||
ctx: &Context<'ctx>,
|
||||
after: Option<String>,
|
||||
before: Option<String>,
|
||||
first: Option<i32>,
|
||||
last: Option<i32>,
|
||||
query: String,
|
||||
) -> Result<Connection<usize, ThreadSummary>, Error> {
|
||||
let nm = ctx.data_unchecked::<Notmuch>();
|
||||
connection::query(
|
||||
after,
|
||||
before,
|
||||
first,
|
||||
last,
|
||||
|after, before, first, last| async move {
|
||||
info!("{after:?} {before:?} {first:?} {last:?} {query}");
|
||||
let mut start = 0usize;
|
||||
let total = nm.count(&query)?;
|
||||
let mut end = total;
|
||||
|
||||
if let Some(after) = after {
|
||||
if after >= total {
|
||||
return Ok(Connection::new(false, false));
|
||||
}
|
||||
start = after + 1;
|
||||
}
|
||||
|
||||
// TODO(wathiede): handle last/end.
|
||||
if let Some(before) = before {
|
||||
if before == 0 {
|
||||
return Ok(Connection::new(false, false));
|
||||
}
|
||||
end = before;
|
||||
}
|
||||
|
||||
let slice: Vec<ThreadSummary> = nm
|
||||
.search(&query, start, first.unwrap_or(20))?
|
||||
.0
|
||||
.into_iter()
|
||||
.map(|ts| ThreadSummary {
|
||||
thread: ts.thread,
|
||||
timestamp: ts.timestamp,
|
||||
date_relative: ts.date_relative,
|
||||
matched: ts.matched,
|
||||
total: ts.total,
|
||||
authors: ts.authors,
|
||||
subject: ts.subject,
|
||||
tags: ts.tags,
|
||||
})
|
||||
.collect();
|
||||
//let mut slice = &res[..];
|
||||
|
||||
/*
|
||||
if let Some(first) = first {
|
||||
slice = &slice[..first.min(slice.len())];
|
||||
end -= first.min(slice.len());
|
||||
} else if let Some(last) = last {
|
||||
slice = &slice[slice.len() - last.min(slice.len())..];
|
||||
start = end - last.min(slice.len());
|
||||
}
|
||||
*/
|
||||
|
||||
let mut connection = Connection::new(start > 0, end < total);
|
||||
connection.edges.extend(
|
||||
slice
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(idx, item)| Edge::new(start + idx, item)),
|
||||
);
|
||||
Ok::<_, Error>(connection)
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn tags<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Vec<Tag>> {
|
||||
let nm = ctx.data_unchecked::<Notmuch>();
|
||||
Ok(nm
|
||||
.tags()?
|
||||
.into_iter()
|
||||
.map(|tag| {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
tag.hash(&mut hasher);
|
||||
let hex = format!("#{:06x}", hasher.finish() % (1 << 24));
|
||||
Tag {
|
||||
name: tag,
|
||||
fg_color: "white".to_string(),
|
||||
bg_color: hex,
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
pub type GraphqlSchema = Schema<QueryRoot, EmptyMutation, EmptySubscription>;
|
||||
@ -1,2 +1,3 @@
|
||||
pub mod error;
|
||||
pub mod graphql;
|
||||
pub mod nm;
|
||||
|
||||
@ -7,7 +7,7 @@ pub fn threadset_to_messages(
|
||||
thread_set: notmuch::ThreadSet,
|
||||
) -> Result<Vec<Message>, error::ServerError> {
|
||||
for t in thread_set.0 {
|
||||
for tn in t.0 {}
|
||||
for _tn in t.0 {}
|
||||
}
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user