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 "protocol_p.h"
11#include "storage/querybuilder.h"
12#include "storage/tagqueryhelper.h"
13#include "utils.h"
14
15using namespace Akonadi;
16using namespace Akonadi::Server;
17
18TagFetchHelper::TagFetchHelper(Connection *connection, const Scope &scope, const Protocol::TagFetchScope &fetchScope)
19 : mConnection(connection)
20 , mScope(scope)
21 , mFetchScope(fetchScope)
22{
23}
24
25QueryBuilder TagFetchHelper::buildAttributeQuery() const
26{
27 QueryBuilder qb(TagAttribute::tableName());
28 qb.addColumn(TagAttribute::tagIdFullColumnName());
29 qb.addColumn(TagAttribute::typeFullColumnName());
30 qb.addColumn(TagAttribute::valueFullColumnName());
31 qb.addSortColumn(TagAttribute::tagIdFullColumnName(), Query::Descending);
32 qb.addJoin(QueryBuilder::InnerJoin, Tag::tableName(), 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;
41}
42
43QueryBuilder 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), [](const QByteArray &ba) {
56 return QVariant(ba);
57 });
58 qb.addValueCondition(TagAttribute::typeColumn(), Query::In, typeNames);
59 }
60
61 if (!qb.exec()) {
62 throw HandlerException("Unable to list tag attributes");
63 }
64
65 qb.query().next();
66 return qb;
67}
68
69QueryBuilder TagFetchHelper::buildTagQuery()
70{
71 QueryBuilder qb(Tag::tableName());
72 qb.addColumn(Tag::idFullColumnName());
73 qb.addColumn(Tag::gidFullColumnName());
74 qb.addColumn(Tag::parentIdFullColumnName());
75
76 qb.addJoin(QueryBuilder::InnerJoin, TagType::tableName(), 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(), Query::Equals, mConnection->context().resource().id());
84 joinCondition.addColumnCondition(TagRemoteIdResourceRelation::tagIdFullColumnName(), Query::Equals, Tag::idFullColumnName());
85 qb.addJoin(QueryBuilder::LeftJoin, TagRemoteIdResourceRelation::tableName(), joinCondition);
86 }
87
88 qb.addSortColumn(Tag::idFullColumnName(), Query::Descending);
89 TagQueryHelper::scopeToQuery(mScope, mConnection->context(), qb);
90 if (!qb.exec()) {
91 throw HandlerException("Unable to list tags");
92 }
93
94 qb.query().next();
95 return qb;
96}
97
98QMap<QByteArray, QByteArray> TagFetchHelper::fetchTagAttributes(qint64 tagId, const Protocol::TagFetchScope &fetchScope)
99{
101
102 auto attributeQb = buildAttributeQuery(tagId, fetchScope);
103 auto &attributeQuery = attributeQb.query();
104 while (attributeQuery.isValid()) {
105 attributes.insert(Utils::variantToByteArray(attributeQuery.value(1)), Utils::variantToByteArray(attributeQuery.value(2)));
106 attributeQuery.next();
107 }
108 attributeQuery.finish();
109 return attributes;
110}
111
112bool TagFetchHelper::fetchTags(std::function<void(Protocol::FetchTagsResponse &&)> &&callback)
113{
114 auto tagQb = buildTagQuery();
115 auto &tagQuery = tagQb.query();
116
117 std::optional<QueryBuilder> attributeQb;
118 if (!mFetchScope.fetchIdOnly()) {
119 attributeQb = buildAttributeQuery();
120 }
121
122 while (tagQuery.isValid()) {
123 const qint64 tagId = tagQuery.value(0).toLongLong();
124 Protocol::FetchTagsResponse response;
125 response.setId(tagId);
126 if (!mFetchScope.fetchIdOnly()) {
127 response.setGid(Utils::variantToByteArray(tagQuery.value(1)));
128 if (tagQuery.value(2).isNull()) {
129 // client indicates invalid or null parent as ID -1
130 response.setParentId(-1);
131 } else {
132 response.setParentId(tagQuery.value(2).toLongLong());
133 }
134 response.setType(Utils::variantToByteArray(tagQuery.value(3)));
135 if (mFetchScope.fetchRemoteID() && mConnection->context().resource().isValid()) {
136 response.setRemoteId(Utils::variantToByteArray(tagQuery.value(4)));
137 }
138
139 if (attributeQb.has_value()) {
140 QMap<QByteArray, QByteArray> tagAttributes;
141 auto &attributeQuery = attributeQb->query();
142 while (attributeQuery.isValid()) {
143 const qint64 id = attributeQuery.value(0).toLongLong();
144 if (id > tagId) {
145 attributeQuery.next();
146 continue;
147 } else if (id < tagId) {
148 break;
149 }
150
151 tagAttributes.insert(Utils::variantToByteArray(attributeQuery.value(1)), Utils::variantToByteArray(attributeQuery.value(2)));
152 attributeQuery.next();
153 }
154
155 response.setAttributes(tagAttributes);
156 }
157 }
158
159 if (callback) {
160 callback(std::move(response));
161 } else {
162 mConnection->sendResponse(std::move(response));
163 }
164
165 tagQuery.next();
166 }
167
168 return true;
169}
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 Sat Dec 21 2024 17:01:42 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.