melib/jmap: use Argument<OBJ> (value or resultreference) where appropriate
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>pull/279/head
parent
d9467d5fcd
commit
31982931f5
|
@ -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"),
|
||||
)))
|
||||
|
|
|
@ -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()])),
|
||||
);
|
||||
|
|
|
@ -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()),
|
||||
);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue