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

KDE's Doxygen guidelines are available online.