summaryrefslogtreecommitdiff
path: root/crates/jmap/src/principal/query.rs
blob: 0ed616ea111a6de645ccdaa8d340e954da1e3241 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
 * SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
 *
 * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
 */

use directory::QueryBy;
use jmap_proto::{
    method::query::{Filter, QueryRequest, QueryResponse, RequestArguments},
    types::collection::Collection,
};
use store::{query::ResultSet, roaring::RoaringBitmap};

use crate::{api::http::HttpSessionData, JMAP};

impl JMAP {
    pub async fn principal_query(
        &self,
        mut request: QueryRequest<RequestArguments>,
        session: &HttpSessionData,
    ) -> trc::Result<QueryResponse> {
        let account_id = request.account_id.document_id();
        let mut result_set = ResultSet {
            account_id,
            collection: Collection::Principal.into(),
            results: RoaringBitmap::new(),
        };
        let mut is_set = true;

        for cond in std::mem::take(&mut request.filter) {
            match cond {
                Filter::Name(name) => {
                    if let Some(principal) = self
                        .core
                        .storage
                        .directory
                        .query(QueryBy::Name(name.as_str()), false)
                        .await?
                    {
                        if is_set || result_set.results.contains(principal.id()) {
                            result_set.results =
                                RoaringBitmap::from_sorted_iter([principal.id()]).unwrap();
                        } else {
                            result_set.results = RoaringBitmap::new();
                        }
                    } else {
                        result_set.results = RoaringBitmap::new();
                    }
                    is_set = false;
                }
                Filter::Email(email) => {
                    let mut ids = RoaringBitmap::new();
                    for id in self
                        .core
                        .email_to_ids(&self.core.storage.directory, &email, session.session_id)
                        .await?
                    {
                        ids.insert(id);
                    }
                    if is_set {
                        result_set.results = ids;
                        is_set = false;
                    } else {
                        result_set.results &= ids;
                    }
                }
                Filter::Type(_) => {}
                other => {
                    return Err(trc::JmapEvent::UnsupportedFilter
                        .into_err()
                        .details(other.to_string()))
                }
            }
        }

        if is_set {
            result_set.results = self
                .get_document_ids(u32::MAX, Collection::Principal)
                .await?
                .unwrap_or_default();
        }

        let (response, paginate) = self.build_query_response(&result_set, &request).await?;

        if let Some(paginate) = paginate {
            self.sort(result_set, Vec::new(), paginate, response).await
        } else {
            Ok(response)
        }
    }
}