Akonadi

searchquery.cpp
1 /*
2  SPDX-FileCopyrightText: 2014 Daniel Vrátil <[email protected]>
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 
14 using namespace Akonadi;
15 
16 class Akonadi::SearchTermPrivate : public QSharedData
17 {
18 public:
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;
29  QList<SearchTerm> terms;
30  bool isNegated = false;
31 };
32 
33 class Akonadi::SearchQueryPrivate : public QSharedData
34 {
35 public:
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 
93 SearchTerm::SearchTerm(SearchTerm::Relation relation)
94  : d(new SearchTermPrivate)
95 {
96  d->relation = relation;
97 }
98 
99 SearchTerm::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 
113 SearchTerm::~SearchTerm() = default;
114 
115 SearchTerm &SearchTerm::operator=(const SearchTerm &other)
116 {
117  d = other.d;
118  return *this;
119 }
120 
121 bool SearchTerm::operator==(const SearchTerm &other) const
122 {
123  return *d == *other.d;
124 }
125 
126 bool 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 
141 SearchTerm::Condition SearchTerm::condition() const
142 {
143  return d->condition;
144 }
145 
146 void 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 
166 SearchTerm::Relation SearchTerm::relation() const
167 {
168  return d->relation;
169 }
170 
171 SearchQuery::SearchQuery(SearchTerm::Relation rel)
172  : d(new SearchQueryPrivate)
173 {
174  d->rootTerm = SearchTerm(rel);
175 }
176 
178  : d(other.d)
179 {
180 }
181 
182 SearchQuery::~SearchQuery()
183 {
184 }
185 
186 SearchQuery &SearchQuery::operator=(const SearchQuery &other)
187 {
188  d = other.d;
189  return *this;
190 }
191 
192 bool SearchQuery::operator==(const SearchQuery &other) const
193 {
194  return *d == *other.d;
195 }
196 
197 bool SearchQuery::isNull() const
198 {
199  return d->rootTerm.isNull();
200 }
201 
203 {
204  return d->rootTerm;
205 }
206 
207 void 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 
222 void SearchQuery::setLimit(int limit)
223 {
224  d->limit = limit;
225 }
226 
228 {
229  return d->limit;
230 }
231 
232 QByteArray 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 
246 SearchQuery 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(QLatin1String("limit"))) {
258  query.d->limit = obj.value(QStringLiteral("limit")).toInt();
259  }
260  return query;
261 }
262 
263 static 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 
293 EmailSearchTerm::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 
308 static 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 
321 ContactSearchTerm::ContactSearchTerm(ContactSearchTerm::ContactSearchField field, const QVariant &value, SearchTerm::Condition condition)
322  : SearchTerm(toKey(field), value, condition)
323 {
324 }
325 
326 QString ContactSearchTerm::toKey(ContactSearchTerm::ContactSearchField field)
327 {
328  return contactSearchFieldMapping().value(field);
329 }
330 
331 ContactSearchTerm::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 
349 IncidenceSearchTerm::IncidenceSearchTerm(IncidenceSearchTerm::IncidenceSearchField field, const QVariant &value, SearchTerm::Condition condition)
350  : SearchTerm(toKey(field), value, condition)
351 {
352 }
353 
354 QString IncidenceSearchTerm::toKey(IncidenceSearchTerm::IncidenceSearchField field)
355 {
356  return incidenceSearchFieldMapping().value(field);
357 }
358 
359 IncidenceSearchTerm::IncidenceSearchField IncidenceSearchTerm::fromKey(const QString &key)
360 {
361  return incidenceSearchFieldMapping().key(key);
362 }
QJsonObject object() const const
static IncidenceSearchField fromKey(const QString &key)
Translates key to field.
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
SearchTerm(SearchTerm::Relation relation=SearchTerm::RelAnd)
Constructs a term where all subterms will be in given relation.
Definition: searchquery.cpp:93
int limit() const
Returns the maximum number of results.
bool isNull() const const
int toInt(int defaultValue) const const
int count(const T &value) const const
QVariantMap toVariantMap() const const
QList< SearchTerm > subTerms() const
Returns all subterms, or an empty list if this is an end term.
QString key() const
Returns key of this end term.
QJsonObject fromVariantMap(const QVariantMap &map)
static QString toKey(ContactSearchField)
Translates field to key.
void setIsNegated(bool negated)
Sets whether the entire term is negated.
QVariant value() const
Returns value of this end term.
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
A query that can be passed to ItemSearchJob or others.
Definition: searchquery.h:116
Definition: item.h:29
static QString toKey(IncidenceSearchField)
Translates field to key.
SearchQuery(SearchTerm::Relation rel=SearchTerm::RelAnd)
Constructs query where all added terms will be in given relation.
void setLimit(int limit)
Sets the maximum number of results.
bool isNegated() const
Returns whether the entire term is negated.
bool contains(const QString &key) const const
static QString toKey(EmailSearchField)
Translates field to key.
static EmailSearchField fromKey(const QString &key)
Translates key to field.
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
QMap::iterator insert(const Key &key, const T &value)
bool operator==(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
void addSubTerm(const SearchTerm &term)
Adds a new subterm to this term.
SearchTerm::Relation relation() const
Returns relation in which all subterms are.
static ContactSearchField fromKey(const QString &key)
Translates key to field.
bool isEmpty() const const
QJsonValue value(const QString &key) const const
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
SearchTerm term() const
Returns the root term.
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.
EmailSearchTerm(EmailSearchField field, const QVariant &value, SearchTerm::Condition condition=SearchTerm::CondEqual)
Constructs an email end term.
QByteArray toJson() const const
void setObject(const QJsonObject &object)
SearchTerm::Condition condition() const
Returns relation between key and value.
Search term represents the actual condition within query.
Definition: searchquery.h:26
EmailSearchField
All fields expect a search string unless noted otherwise.
Definition: searchquery.h:186
QFuture< void > map(Sequence &sequence, MapFunctor function)
char * toString(const EngineQuery &query)
Helper integration between Akonadi and Qt.
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Dec 3 2023 04:05:26 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.