Akonadi

tagfetchhelper.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 "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
14using namespace Akonadi;
15using namespace Akonadi::Server;
16
17TagFetchHelper::TagFetchHelper(Connection *connection, const Scope &scope, const Protocol::TagFetchScope &fetchScope)
18 : mConnection(connection)
19 , mScope(scope)
20 , mFetchScope(fetchScope)
21{
22}
23
24QSqlQuery 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
42QSqlQuery 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
68QSqlQuery 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
97QMap<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
110bool 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}
An Connection represents one connection of a client to the server.
Definition connection.h:39
Helper class to construct arbitrary SQL queries.
@ InnerJoin
NOTE: only supported for UPDATE and SELECT queries.
@ LeftJoin
NOTE: only supported for SELECT queries.
Represents a WHERE condition tree.
Definition query.h:62
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
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
void scopeToQuery(const Scope &scope, const CommandContext &context, QueryBuilder &qb)
Add conditions to qb for the given item operation scope scope.
Helper integration between Akonadi and Qt.
iterator insert(const Key &key, const T &value)
void finish()
bool isValid() const const
bool next()
QVariant value(const QString &name) const const
bool isNull() const const
qlonglong toLongLong(bool *ok) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:38 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.