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
24QueryBuilder 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;
40}
41
42QueryBuilder 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;
66}
67
68QueryBuilder 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;
95}
96
97QMap<QByteArray, QByteArray> TagFetchHelper::fetchTagAttributes(qint64 tagId, const Protocol::TagFetchScope &fetchScope)
98{
100
101 auto attributeQb = buildAttributeQuery(tagId, fetchScope);
102 auto &attributeQuery = attributeQb.query();
103 while (attributeQuery.isValid()) {
104 attributes.insert(Utils::variantToByteArray(attributeQuery.value(1)), Utils::variantToByteArray(attributeQuery.value(2)));
105 attributeQuery.next();
106 }
107 attributeQuery.finish();
108 return attributes;
109}
110
111bool TagFetchHelper::fetchTags()
112{
113 auto tagQb = buildTagQuery();
114 auto &tagQuery = tagQb.query();
115
116 std::optional<QueryBuilder> attributeQb;
117 if (!mFetchScope.fetchIdOnly()) {
118 attributeQb = buildAttributeQuery();
119 }
120
121 while (tagQuery.isValid()) {
122 const qint64 tagId = tagQuery.value(0).toLongLong();
123 Protocol::FetchTagsResponse response;
124 response.setId(tagId);
125 if (!mFetchScope.fetchIdOnly()) {
126 response.setGid(Utils::variantToByteArray(tagQuery.value(1)));
127 if (tagQuery.value(2).isNull()) {
128 // client indicates invalid or null parent as ID -1
129 response.setParentId(-1);
130 } else {
131 response.setParentId(tagQuery.value(2).toLongLong());
132 }
133 response.setType(Utils::variantToByteArray(tagQuery.value(3)));
134 if (mFetchScope.fetchRemoteID() && mConnection->context().resource().isValid()) {
135 response.setRemoteId(Utils::variantToByteArray(tagQuery.value(4)));
136 }
137
138 if (attributeQb.has_value()) {
139 QMap<QByteArray, QByteArray> tagAttributes;
140 auto &attributeQuery = attributeQb->query();
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)), Utils::variantToByteArray(attributeQuery.value(2)));
151 attributeQuery.next();
152 }
153
154 response.setAttributes(tagAttributes);
155 }
156 }
157
158 mConnection->sendResponse(std::move(response));
159
160 tagQuery.next();
161 }
162
163 return true;
164}
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)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:08:30 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.