Akonadi

tagfetchhelper.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 "tagfetchhelper.h"
8 #include "handler.h"
9 #include "connection.h"
10 #include "utils.h"
11 #include "storage/querybuilder.h"
12 #include "storage/tagqueryhelper.h"
13 
14 using namespace Akonadi;
15 using namespace Akonadi::Server;
16 
17 TagFetchHelper::TagFetchHelper(Connection *connection, const Scope &scope, const Protocol::TagFetchScope &fetchScope)
18  : mConnection(connection)
19  , mScope(scope)
20  , mFetchScope(fetchScope)
21 {
22 }
23 
24 QSqlQuery TagFetchHelper::buildAttributeQuery() const
25 {
26  QueryBuilder qb(TagAttribute::tableName());
27  qb.addColumn(TagAttribute::tagIdFullColumnName());
28  qb.addColumn(TagAttribute::typeFullColumnName());
29  qb.addColumn(TagAttribute::valueFullColumnName());
30  qb.addSortColumn(TagAttribute::tagIdFullColumnName(), Query::Descending);
31  qb.addJoin(QueryBuilder::InnerJoin, Tag::tableName(),
32  TagAttribute::tagIdFullColumnName(), Tag::idFullColumnName());
33  TagQueryHelper::scopeToQuery(mScope, mConnection->context(), qb);
34 
35  if (!qb.exec()) {
36  throw HandlerException("Unable to list tag attributes");
37  }
38 
39  qb.query().next();
40  return qb.query();
41 }
42 
43 QSqlQuery TagFetchHelper::buildAttributeQuery(qint64 id, const Protocol::TagFetchScope &fetchScope)
44 {
45  QueryBuilder qb(TagAttribute::tableName());
46  qb.addColumn(TagAttribute::tagIdColumn());
47  qb.addColumn(TagAttribute::typeColumn());
48  qb.addColumn(TagAttribute::valueColumn());
49  qb.addSortColumn(TagAttribute::tagIdColumn(), Query::Descending);
50 
51  qb.addValueCondition(TagAttribute::tagIdColumn(), Query::Equals, id);
52  if (!fetchScope.fetchAllAttributes() && !fetchScope.attributes().isEmpty()) {
53  QVariantList typeNames;
54  const auto attrs = fetchScope.attributes();
55  std::transform(attrs.cbegin(), attrs.cend(), std::back_inserter(typeNames),
56  [](const QByteArray &ba) { return QVariant(ba); });
57  qb.addValueCondition(TagAttribute::typeColumn(), Query::In, typeNames);
58  }
59 
60  if (!qb.exec()) {
61  throw HandlerException("Unable to list tag attributes");
62  }
63 
64  qb.query().next();
65  return qb.query();
66 }
67 
68 QSqlQuery TagFetchHelper::buildTagQuery()
69 {
70  QueryBuilder qb(Tag::tableName());
71  qb.addColumn(Tag::idFullColumnName());
72  qb.addColumn(Tag::gidFullColumnName());
73  qb.addColumn(Tag::parentIdFullColumnName());
74 
75  qb.addJoin(QueryBuilder::InnerJoin, TagType::tableName(),
76  Tag::typeIdFullColumnName(), TagType::idFullColumnName());
77  qb.addColumn(TagType::nameFullColumnName());
78 
79  // Expose tag's remote ID only to resources
80  if (mFetchScope.fetchRemoteID() && mConnection->context().resource().isValid()) {
81  qb.addColumn(TagRemoteIdResourceRelation::remoteIdFullColumnName());
82  Query::Condition joinCondition;
83  joinCondition.addValueCondition(TagRemoteIdResourceRelation::resourceIdFullColumnName(),
84  Query::Equals, mConnection->context().resource().id());
85  joinCondition.addColumnCondition(TagRemoteIdResourceRelation::tagIdFullColumnName(),
86  Query::Equals, Tag::idFullColumnName());
87  qb.addJoin(QueryBuilder::LeftJoin, TagRemoteIdResourceRelation::tableName(), joinCondition);
88  }
89 
90  qb.addSortColumn(Tag::idFullColumnName(), Query::Descending);
91  TagQueryHelper::scopeToQuery(mScope, mConnection->context(), qb);
92  if (!qb.exec()) {
93  throw HandlerException("Unable to list tags");
94  }
95 
96  qb.query().next();
97  return qb.query();
98 }
99 
100 QMap<QByteArray, QByteArray> TagFetchHelper::fetchTagAttributes(qint64 tagId,
101  const Protocol::TagFetchScope &fetchScope)
102 {
103  QMap<QByteArray, QByteArray> attributes;
104 
105  QSqlQuery attributeQuery = buildAttributeQuery(tagId, fetchScope);
106  while (attributeQuery.isValid()) {
107  attributes.insert(Utils::variantToByteArray(attributeQuery.value(1)),
108  Utils::variantToByteArray(attributeQuery.value(2)));
109  attributeQuery.next();
110  }
111  attributeQuery.finish();
112  return attributes;
113 }
114 
115 bool TagFetchHelper::fetchTags()
116 {
117  QSqlQuery tagQuery = buildTagQuery();
118  QSqlQuery attributeQuery;
119  if (!mFetchScope.fetchIdOnly()) {
120  attributeQuery = buildAttributeQuery();
121  }
122 
123  while (tagQuery.isValid()) {
124  const qint64 tagId = tagQuery.value(0).toLongLong();
125  Protocol::FetchTagsResponse response;
126  response.setId(tagId);
127  if (!mFetchScope.fetchIdOnly()) {
128  response.setGid(Utils::variantToByteArray(tagQuery.value(1)));
129  if (tagQuery.value(2).isNull()) {
130  // client indicates invalid or null parent as ID -1
131  response.setParentId(-1);
132  } else {
133  response.setParentId(tagQuery.value(2).toLongLong());
134  }
135  response.setType(Utils::variantToByteArray(tagQuery.value(3)));
136  if (mFetchScope.fetchRemoteID() && mConnection->context().resource().isValid()) {
137  response.setRemoteId(Utils::variantToByteArray(tagQuery.value(4)));
138  }
139 
140  QMap<QByteArray, QByteArray> tagAttributes;
141  while (attributeQuery.isValid()) {
142  const qint64 id = attributeQuery.value(0).toLongLong();
143  if (id > tagId) {
144  attributeQuery.next();
145  continue;
146  } else if (id < tagId) {
147  break;
148  }
149 
150  tagAttributes.insert(Utils::variantToByteArray(attributeQuery.value(1)),
151  Utils::variantToByteArray(attributeQuery.value(2)));
152  attributeQuery.next();
153  }
154 
155  response.setAttributes(tagAttributes);
156  }
157 
158  mConnection->sendResponse(std::move(response));
159 
160  tagQuery.next();
161  }
162  attributeQuery.finish();
163  tagQuery.finish();
164 
165  return true;
166 }
qlonglong toLongLong(bool *ok) const const
NOTE: only supported for UPDATE and SELECT queries.
Definition: querybuilder.h:49
void scopeToQuery(const Scope &scope, const CommandContext &context, QueryBuilder &qb)
Add conditions to qb for the given item operation scope scope.
bool isNull() const const
QVariant value(int index) const const
bool next()
void addColumnCondition(const QString &column, CompareOperator op, const QString &column2)
Add a WHERE condition which compares a column with another column.
Definition: query.cpp:22
NOTE: only supported for SELECT queries.
Definition: querybuilder.h:51
bool isValid() const const
void finish()
Helper integration between Akonadi and Qt.
QMap::iterator insert(const Key &key, const T &value)
Represents a WHERE condition tree.
Definition: query.h:64
Helper class to construct arbitrary SQL queries.
Definition: querybuilder.h:32
An Connection represents one connection of a client to the server.
Definition: connection.h:40
void addValueCondition(const QString &column, CompareOperator op, const QVariant &value)
Add a WHERE condition which compares a column with a given value.
Definition: query.cpp:12
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sun Jul 12 2020 23:16:58 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.