melib/jmap: use Argument<OBJ> (value or resultreference) where appropriate

Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
pull/279/head
Manos Pitsidianakis 2023-08-28 14:31:05 +03:00
parent d9467d5fcd
commit 31982931f5
Signed by: Manos Pitsidianakis
GPG Key ID: 7729C7707F7E09D0
5 changed files with 79 additions and 44 deletions

View File

@ -243,7 +243,11 @@ impl JmapConnection {
let prev_seq = req.add_call(&email_changes_call);
let email_get_call: EmailGet = EmailGet::new(
Get::new()
.ids(Some(JmapArgument::reference(
.ids(Some(Argument::reference::<
EmailChanges,
EmailObject,
EmailObject,
>(
prev_seq,
ResultField::<EmailChanges, EmailObject>::new("/created"),
)))
@ -251,20 +255,26 @@ impl JmapConnection {
);
req.add_call(&email_get_call);
let mailbox_id: Id<MailboxObject>;
if let Some(mailbox) = self.store.mailboxes.read().unwrap().get(&mailbox_hash) {
if let Some(email_query_state) = mailbox.email_query_state.lock().unwrap().clone() {
mailbox_id = mailbox.id.clone();
let email_query_changes_call = EmailQueryChanges::new(
QueryChanges::new(self.mail_account_id().clone(), email_query_state)
.filter(Some(Filter::Condition(
EmailFilterCondition::new()
.in_mailbox(Some(mailbox.id.clone()))
.in_mailbox(Some(mailbox_id.clone()))
.into(),
))),
);
let seq_no = req.add_call(&email_query_changes_call);
let email_get_call: EmailGet = EmailGet::new(
Get::new()
.ids(Some(JmapArgument::reference(
.ids(Some(Argument::reference::<
EmailQueryChanges,
EmailObject,
EmailObject,
>(
seq_no,
ResultField::<EmailQueryChanges, EmailObject>::new("/removed"),
)))

View File

@ -650,7 +650,7 @@ impl MailBackend for JmapType {
mailboxes_lck[&destination_mailbox_hash].id.clone(),
)
};
let mut update_map: IndexMap<Id<EmailObject>, Value> = IndexMap::default();
let mut update_map: IndexMap<Argument<Id<EmailObject>>, Value> = IndexMap::default();
let mut update_keywords: IndexMap<String, Value> = IndexMap::default();
update_keywords.insert(
format!("mailboxIds/{}", &destination_mailbox_id),
@ -667,7 +667,10 @@ impl MailBackend for JmapType {
if let Some(id) = store.id_store.lock().unwrap().get(&env_hash) {
// ids.push(id.clone());
// id_map.insert(id.clone(), env_hash);
update_map.insert(id.clone(), serde_json::json!(update_keywords.clone()));
update_map.insert(
Argument::from(id.clone()),
serde_json::json!(update_keywords.clone()),
);
}
}
}
@ -719,7 +722,7 @@ impl MailBackend for JmapType {
let store = self.store.clone();
let connection = self.connection.clone();
Ok(Box::pin(async move {
let mut update_map: IndexMap<Id<EmailObject>, Value> = IndexMap::default();
let mut update_map: IndexMap<Argument<Id<EmailObject>>, Value> = IndexMap::default();
let mut ids: Vec<Id<EmailObject>> = Vec::with_capacity(env_hashes.rest.len() + 1);
let mut id_map: IndexMap<Id<EmailObject>, EnvelopeHash> = IndexMap::default();
let mut update_keywords: IndexMap<String, Value> = IndexMap::default();
@ -763,7 +766,10 @@ impl MailBackend for JmapType {
if let Some(id) = store.id_store.lock().unwrap().get(&hash) {
ids.push(id.clone());
id_map.insert(id.clone(), hash);
update_map.insert(id.clone(), serde_json::json!(update_keywords.clone()));
update_map.insert(
Argument::from(id.clone()),
serde_json::json!(update_keywords.clone()),
);
}
}
}
@ -779,7 +785,7 @@ impl MailBackend for JmapType {
req.add_call(&email_set_call);
let email_call: EmailGet = EmailGet::new(
Get::new()
.ids(Some(JmapArgument::Value(ids)))
.ids(Some(Argument::Value(ids)))
.account_id(conn.mail_account_id())
.properties(Some(vec!["keywords".to_string()])),
);

View File

@ -205,7 +205,7 @@ pub async fn get_message_list(
pub async fn get_message(conn: &JmapConnection, ids: &[String]) -> Result<Vec<Envelope>> {
let email_call: EmailGet = EmailGet::new(
Get::new()
.ids(Some(JmapArgument::value(ids.to_vec())))
.ids(Some(Argument::value(ids.to_vec())))
.account_id(conn.mail_account_id().to_string()),
);
@ -304,9 +304,12 @@ impl EmailFetchState {
let email_call: EmailGet = EmailGet::new(
Get::new()
.ids(Some(JmapArgument::reference(
prev_seq,
EmailQuery::RESULT_FIELD_IDS,
.ids(Some(Argument::reference::<
EmailQuery,
EmailObject,
EmailObject,
>(
prev_seq, EmailQuery::RESULT_FIELD_IDS
)))
.account_id(conn.mail_account_id().clone()),
);

View File

@ -41,6 +41,12 @@ mod argument;
pub use argument::*;
use indexmap::IndexMap;
pub type PatchObject = Value;
impl Object for PatchObject {
const NAME: &'static str = "PatchObject";
}
use super::{deserialize_from_str, protocol::Method};
pub trait Object {
const NAME: &'static str;
@ -288,6 +294,14 @@ impl Object for BlobObject {
const NAME: &'static str = "Blob";
}
#[derive(Clone, Copy, Deserialize, Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct BlobGet;
impl Method<BlobObject> for BlobGet {
const NAME: &'static str = "Blob/get";
}
/// #`get`
///
/// Objects of type `Foo` are fetched via a call to `Foo/get`.
@ -306,7 +320,7 @@ where
pub account_id: Id<Account>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(flatten)]
pub ids: Option<JmapArgument<Vec<Id<OBJ>>>>,
pub ids: Option<Argument<Vec<Id<OBJ>>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub properties: Option<Vec<String>>,
#[serde(skip)]
@ -332,13 +346,13 @@ where
account_id: Id<Account>
);
_impl!(
/// - ids: `Option<JmapArgument<Vec<String>>>`
/// - ids: `Option<Argument<Vec<String>>>`
///
/// The ids of the Foo objects to return. If `None`, then *all*
/// records of the data type are returned, if this is
/// supported for that data type and the number of records
/// does not exceed the `max_objects_in_get` limit.
ids: Option<JmapArgument<Vec<Id<OBJ>>>>
ids: Option<Argument<Vec<Id<OBJ>>>>
);
_impl!(
/// - properties: `Option<Vec<String>>`
@ -385,11 +399,12 @@ impl<OBJ: Object + Serialize + std::fmt::Debug> Serialize for Get<OBJ> {
}
match self.ids.as_ref() {
None => {}
Some(JmapArgument::Value(ref v)) => state.serialize_field("ids", v)?,
Some(JmapArgument::ResultReference {
Some(Argument::Value(ref v)) => state.serialize_field("ids", v)?,
Some(Argument::ResultReference {
ref result_of,
ref name,
ref path,
..
}) => {
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
@ -573,7 +588,7 @@ pub struct ResultField<M: Method<OBJ>, OBJ: Object> {
}
impl<M: Method<OBJ>, OBJ: Object> ResultField<M, OBJ> {
pub fn new(field: &'static str) -> Self {
pub const fn new(field: &'static str) -> Self {
Self {
field,
_ph: PhantomData,
@ -581,22 +596,11 @@ impl<M: Method<OBJ>, OBJ: Object> ResultField<M, OBJ> {
}
}
// error[E0723]: trait bounds other than `Sized` on const fn parameters are
// unstable --> melib/src/backends/jmap/rfc8620.rs:626:6
// |
// 626 | impl<M: Method<OBJ>, OBJ: Object> ResultField<M, OBJ> {
// | ^
// |
// = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
// = help: add `#![feature(const_fn)]` to the crate attributes to enable
// impl<M: Method<OBJ>, OBJ: Object> ResultField<M, OBJ> {
// pub const fn new(field: &'static str) -> Self {
// Self {
// field,
// _ph: PhantomData,
// }
// }
// }
impl<M: Method<OBJ>, OBJ: Object> From<&'static str> for ResultField<M, OBJ> {
fn from(field: &'static str) -> Self {
Self::new(field)
}
}
/// #`changes`
///
@ -751,7 +755,7 @@ where
///
/// The client MUST omit any properties that may only be set by the
/// server (for example, the `id` property on most object types).
pub create: Option<IndexMap<Id<OBJ>, OBJ>>,
pub create: Option<IndexMap<Argument<Id<OBJ>>, OBJ>>,
/// o update: `Id[PatchObject]|null`
///
/// A map of an id to a Patch object to apply to the current Foo
@ -795,12 +799,12 @@ where
/// is also a valid PatchObject. The client may choose to optimise
/// network usage by just sending the diff or may send the whole
/// object; the server processes it the same either way.
pub update: Option<IndexMap<Id<OBJ>, Value>>,
pub update: Option<IndexMap<Argument<Id<OBJ>>, PatchObject>>,
/// o destroy: `Id[]|null`
///
/// A list of ids for Foo objects to permanently delete, or null if no
/// objects are to be destroyed.
pub destroy: Option<Vec<Id<OBJ>>>,
pub destroy: Option<Vec<Argument<Id<OBJ>>>>,
}
impl<OBJ> Set<OBJ>
@ -828,7 +832,9 @@ where
/// state.
if_in_state: Option<State<OBJ>>
);
_impl!(update: Option<IndexMap<Id<OBJ>, Value>>);
_impl!(update: Option<IndexMap<Argument<Id<OBJ>>, PatchObject>>);
_impl!(create: Option<IndexMap<Argument<Id<OBJ>>, OBJ>>);
_impl!(destroy: Option<Vec<Argument<Id<OBJ>>>>);
}
impl<OBJ> Default for Set<OBJ>

View File

@ -19,15 +19,18 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use std::hash::Hash;
use crate::jmap::{
protocol::Method,
rfc8620::{Object, ResultField},
};
#[derive(Deserialize, Serialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub enum JmapArgument<T: Clone> {
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, Hash, Debug)]
#[serde(rename_all = "camelCase", untagged)]
pub enum Argument<T: Clone + PartialEq + Eq + Hash> {
Value(T),
#[serde(rename_all = "camelCase")]
ResultReference {
result_of: String,
name: String,
@ -35,14 +38,15 @@ pub enum JmapArgument<T: Clone> {
},
}
impl<T: Clone> JmapArgument<T> {
impl<T: Clone + PartialEq + Eq + Hash> Argument<T> {
pub fn value(v: T) -> Self {
Self::Value(v)
}
pub fn reference<M, OBJ>(result_of: usize, path: ResultField<M, OBJ>) -> Self
pub fn reference<M, OBJ, MethodOBJ>(result_of: usize, path: ResultField<M, MethodOBJ>) -> Self
where
M: Method<OBJ>,
M: Method<MethodOBJ>,
MethodOBJ: Object,
OBJ: Object,
{
Self::ResultReference {
@ -52,3 +56,9 @@ impl<T: Clone> JmapArgument<T> {
}
}
}
impl<T: Clone + PartialEq + Eq + Hash> From<T> for Argument<T> {
fn from(v: T) -> Self {
Self::Value(v)
}
}