Akonadi

searchquery.cpp
1/*
2 SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "searchquery.h"
8#include "akonadicore_debug.h"
9
10#include <QJsonDocument>
11#include <QJsonObject>
12#include <QVariant>
13
14using namespace Akonadi;
15
16class Akonadi::SearchTermPrivate : public QSharedData
17{
18public:
19 bool operator==(const SearchTermPrivate &other) const
20 {
21 return relation == other.relation && isNegated == other.isNegated && terms == other.terms && key == other.key && value == other.value
22 && condition == other.condition;
23 }
24
25 QString key;
26 QVariant value;
27 SearchTerm::Condition condition = SearchTerm::CondEqual;
28 SearchTerm::Relation relation = SearchTerm::RelAnd;
30 bool isNegated = false;
31};
32
33class Akonadi::SearchQueryPrivate : public QSharedData
34{
35public:
36 bool operator==(const SearchQueryPrivate &other) const
37 {
38 return rootTerm == other.rootTerm && limit == other.limit;
39 }
40
41 static QVariantMap termToJSON(const SearchTerm &term)
42 {
43 const QList<SearchTerm> &subTerms = term.subTerms();
44 QVariantMap termJSON;
45 termJSON.insert(QStringLiteral("negated"), term.isNegated());
46 if (subTerms.isEmpty()) {
47 if (!term.isNull()) {
48 termJSON.insert(QStringLiteral("key"), term.key());
49 termJSON.insert(QStringLiteral("value"), term.value());
50 termJSON.insert(QStringLiteral("cond"), static_cast<int>(term.condition()));
51 }
52 } else {
53 termJSON.insert(QStringLiteral("rel"), static_cast<int>(term.relation()));
54 QVariantList subTermsJSON;
55 subTermsJSON.reserve(subTerms.count());
56 for (const SearchTerm &term : std::as_const(subTerms)) {
57 subTermsJSON.append(termToJSON(term));
58 }
59 termJSON.insert(QStringLiteral("subTerms"), subTermsJSON);
60 }
61
62 return termJSON;
63 }
64
65 static SearchTerm JSONToTerm(const QVariantMap &map)
66 {
67 if (map.isEmpty()) {
68 return SearchTerm();
69 } else if (map.contains(QStringLiteral("key"))) {
70 SearchTerm term(map[QStringLiteral("key")].toString(),
71 map[QStringLiteral("value")],
72 static_cast<SearchTerm::Condition>(map[QStringLiteral("cond")].toInt()));
73 term.setIsNegated(map[QStringLiteral("negated")].toBool());
74 return term;
75 } else if (map.contains(QStringLiteral("rel"))) {
76 SearchTerm term(static_cast<SearchTerm::Relation>(map[QStringLiteral("rel")].toInt()));
77 term.setIsNegated(map[QStringLiteral("negated")].toBool());
78 const QList<QVariant> list = map[QStringLiteral("subTerms")].toList();
79 for (const QVariant &var : list) {
80 term.addSubTerm(JSONToTerm(var.toMap()));
81 }
82 return term;
83 } else {
84 qCWarning(AKONADICORE_LOG) << "Invalid JSON for term: " << map;
85 return SearchTerm();
86 }
87 }
88
89 SearchTerm rootTerm;
90 int limit = -1;
91};
92
93SearchTerm::SearchTerm(SearchTerm::Relation relation)
94 : d(new SearchTermPrivate)
95{
96 d->relation = relation;
97}
98
99SearchTerm::SearchTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition)
100 : d(new SearchTermPrivate)
101{
102 d->relation = RelAnd;
103 d->key = key;
104 d->value = value;
105 d->condition = condition;
106}
107
109 : d(other.d)
110{
111}
112
113SearchTerm::~SearchTerm() = default;
114
115SearchTerm &SearchTerm::operator=(const SearchTerm &other)
116{
117 d = other.d;
118 return *this;
119}
120
121bool SearchTerm::operator==(const SearchTerm &other) const
122{
123 return *d == *other.d;
124}
125
126bool SearchTerm::isNull() const
127{
128 return d->key.isEmpty() && d->value.isNull() && d->terms.isEmpty();
129}
130
132{
133 return d->key;
134}
135
137{
138 return d->value;
139}
140
141SearchTerm::Condition SearchTerm::condition() const
142{
143 return d->condition;
144}
145
146void SearchTerm::setIsNegated(bool negated)
147{
148 d->isNegated = negated;
149}
150
152{
153 return d->isNegated;
154}
155
157{
158 d->terms << term;
159}
160
162{
163 return d->terms;
164}
165
166SearchTerm::Relation SearchTerm::relation() const
167{
168 return d->relation;
169}
170
171SearchQuery::SearchQuery(SearchTerm::Relation rel)
172 : d(new SearchQueryPrivate)
173{
174 d->rootTerm = SearchTerm(rel);
175}
176
178 : d(other.d)
179{
180}
181
182SearchQuery::~SearchQuery()
183{
184}
185
186SearchQuery &SearchQuery::operator=(const SearchQuery &other)
187{
188 d = other.d;
189 return *this;
190}
191
192bool SearchQuery::operator==(const SearchQuery &other) const
193{
194 return *d == *other.d;
195}
196
197bool SearchQuery::isNull() const
198{
199 return d->rootTerm.isNull();
200}
201
203{
204 return d->rootTerm;
205}
206
207void SearchQuery::addTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition)
208{
209 addTerm(SearchTerm(key, value, condition));
210}
211
213{
214 d->rootTerm.addSubTerm(term);
215}
216
218{
219 d->rootTerm = term;
220}
221
223{
224 d->limit = limit;
225}
226
228{
229 return d->limit;
230}
231
232QByteArray SearchQuery::toJSON() const
233{
234 QVariantMap root;
235 if (!d->rootTerm.isNull()) {
236 root = SearchQueryPrivate::termToJSON(d->rootTerm);
237 root.insert(QStringLiteral("limit"), d->limit);
238 }
239
241 QJsonDocument jdoc;
242 jdoc.setObject(jo);
243 return jdoc.toJson();
244}
245
246SearchQuery SearchQuery::fromJSON(const QByteArray &jsonData)
247{
249 const QJsonDocument json = QJsonDocument::fromJson(jsonData, &error);
250 if (error.error != QJsonParseError::NoError || json.isNull()) {
251 return SearchQuery();
252 }
253
255 const QJsonObject obj = json.object();
256 query.d->rootTerm = SearchQueryPrivate::JSONToTerm(obj.toVariantMap());
257 if (obj.contains(QLatin1StringView("limit"))) {
258 query.d->limit = obj.value(QStringLiteral("limit")).toInt();
259 }
260 return query;
261}
262
263static QMap<EmailSearchTerm::EmailSearchField, QString> emailSearchFieldMapping()
264{
266 if (mapping.isEmpty()) {
267 mapping.insert(EmailSearchTerm::Body, QStringLiteral("body"));
268 mapping.insert(EmailSearchTerm::Headers, QStringLiteral("headers"));
269 mapping.insert(EmailSearchTerm::Subject, QStringLiteral("subject"));
270 mapping.insert(EmailSearchTerm::Message, QStringLiteral("message"));
271 mapping.insert(EmailSearchTerm::HeaderFrom, QStringLiteral("from"));
272 mapping.insert(EmailSearchTerm::HeaderTo, QStringLiteral("to"));
273 mapping.insert(EmailSearchTerm::HeaderCC, QStringLiteral("cc"));
274 mapping.insert(EmailSearchTerm::HeaderBCC, QStringLiteral("bcc"));
275 mapping.insert(EmailSearchTerm::HeaderReplyTo, QStringLiteral("replyto"));
276 mapping.insert(EmailSearchTerm::HeaderOrganization, QStringLiteral("organization"));
277 mapping.insert(EmailSearchTerm::HeaderListId, QStringLiteral("listid"));
278 mapping.insert(EmailSearchTerm::HeaderResentFrom, QStringLiteral("resentfrom"));
279 mapping.insert(EmailSearchTerm::HeaderXLoop, QStringLiteral("xloop"));
280 mapping.insert(EmailSearchTerm::HeaderXMailingList, QStringLiteral("xmailinglist"));
281 mapping.insert(EmailSearchTerm::HeaderXSpamFlag, QStringLiteral("xspamflag"));
282 mapping.insert(EmailSearchTerm::HeaderDate, QStringLiteral("date"));
283 mapping.insert(EmailSearchTerm::HeaderOnlyDate, QStringLiteral("onlydate"));
284 mapping.insert(EmailSearchTerm::MessageStatus, QStringLiteral("messagestatus"));
285 mapping.insert(EmailSearchTerm::MessageTag, QStringLiteral("messagetag"));
286 mapping.insert(EmailSearchTerm::ByteSize, QStringLiteral("size"));
287 mapping.insert(EmailSearchTerm::Attachment, QStringLiteral("attachment"));
288 }
289
290 return mapping;
291}
292
293EmailSearchTerm::EmailSearchTerm(EmailSearchTerm::EmailSearchField field, const QVariant &value, SearchTerm::Condition condition)
294 : SearchTerm(toKey(field), value, condition)
295{
296}
297
299{
300 return emailSearchFieldMapping().value(field);
301}
302
304{
305 return emailSearchFieldMapping().key(key);
306}
307
308static QMap<ContactSearchTerm::ContactSearchField, QString> contactSearchFieldMapping()
309{
311 if (mapping.isEmpty()) {
312 mapping.insert(ContactSearchTerm::Name, QStringLiteral("name"));
313 mapping.insert(ContactSearchTerm::Nickname, QStringLiteral("nickname"));
314 mapping.insert(ContactSearchTerm::Email, QStringLiteral("email"));
315 mapping.insert(ContactSearchTerm::Uid, QStringLiteral("uid"));
316 mapping.insert(ContactSearchTerm::All, QStringLiteral("all"));
317 }
318 return mapping;
319}
320
321ContactSearchTerm::ContactSearchTerm(ContactSearchTerm::ContactSearchField field, const QVariant &value, SearchTerm::Condition condition)
322 : SearchTerm(toKey(field), value, condition)
323{
324}
325
326QString ContactSearchTerm::toKey(ContactSearchTerm::ContactSearchField field)
327{
328 return contactSearchFieldMapping().value(field);
329}
330
331ContactSearchTerm::ContactSearchField ContactSearchTerm::fromKey(const QString &key)
332{
333 return contactSearchFieldMapping().key(key);
334}
335
337{
339 if (mapping.isEmpty()) {
340 mapping.insert(IncidenceSearchTerm::All, QStringLiteral("all"));
341 mapping.insert(IncidenceSearchTerm::PartStatus, QStringLiteral("partstatus"));
342 mapping.insert(IncidenceSearchTerm::Organizer, QStringLiteral("organizer"));
343 mapping.insert(IncidenceSearchTerm::Summary, QStringLiteral("summary"));
344 mapping.insert(IncidenceSearchTerm::Location, QStringLiteral("location"));
345 }
346 return mapping;
347}
348
349IncidenceSearchTerm::IncidenceSearchTerm(IncidenceSearchTerm::IncidenceSearchField field, const QVariant &value, SearchTerm::Condition condition)
350 : SearchTerm(toKey(field), value, condition)
351{
352}
353
354QString IncidenceSearchTerm::toKey(IncidenceSearchTerm::IncidenceSearchField field)
355{
356 return incidenceSearchFieldMapping().value(field);
357}
358
359IncidenceSearchTerm::IncidenceSearchField IncidenceSearchTerm::fromKey(const QString &key)
360{
361 return incidenceSearchFieldMapping().key(key);
362}
static ContactSearchField fromKey(const QString &key)
Translates key to field.
static QString toKey(ContactSearchField)
Translates field to key.
static EmailSearchField fromKey(const QString &key)
Translates key to field.
EmailSearchTerm(EmailSearchField field, const QVariant &value, SearchTerm::Condition condition=SearchTerm::CondEqual)
Constructs an email end term.
static QString toKey(EmailSearchField)
Translates field to key.
EmailSearchField
All fields expect a search string unless noted otherwise.
static IncidenceSearchField fromKey(const QString &key)
Translates key to field.
static QString toKey(IncidenceSearchField)
Translates field to key.
A query that can be passed to ItemSearchJob or others.
void setTerm(const SearchTerm &term)
Sets the root term.
void addTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition=SearchTerm::CondEqual)
Adds a new term.
void setLimit(int limit)
Sets the maximum number of results.
int limit() const
Returns the maximum number of results.
SearchQuery(SearchTerm::Relation rel=SearchTerm::RelAnd)
Constructs query where all added terms will be in given relation.
SearchTerm term() const
Returns the root term.
Search term represents the actual condition within query.
Definition searchquery.h:27
QVariant value() const
Returns value of this end term.
QString key() const
Returns key of this end term.
void addSubTerm(const SearchTerm &term)
Adds a new subterm to this term.
void setIsNegated(bool negated)
Sets whether the entire term is negated.
SearchTerm::Condition condition() const
Returns relation between key and value.
SearchTerm(SearchTerm::Relation relation=SearchTerm::RelAnd)
Constructs a term where all subterms will be in given relation.
bool isNegated() const
Returns whether the entire term is negated.
QList< SearchTerm > subTerms() const
Returns all subterms, or an empty list if this is an end term.
SearchTerm::Relation relation() const
Returns relation in which all subterms are.
Helper integration between Akonadi and Qt.
char * toString(const EngineQuery &query)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
A glue between Qt and the standard library.
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
bool isNull() const const
QJsonObject object() const const
void setObject(const QJsonObject &object)
QByteArray toJson(JsonFormat format) const const
bool contains(QLatin1StringView key) const const
QJsonObject fromVariantMap(const QVariantMap &map)
QVariantMap toVariantMap() const const
QJsonValue value(QLatin1StringView key) const const
int toInt(int defaultValue) const const
qsizetype count() const const
bool isEmpty() const const
iterator insert(const Key &key, const T &value)
bool isEmpty() const const
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 17 2024 11:54:40 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.