File indexing completed on 2024-06-23 05:07:03
0001 /* 0002 SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "tagfetchhelper.h" 0008 #include "connection.h" 0009 #include "handler.h" 0010 #include "storage/querybuilder.h" 0011 #include "storage/tagqueryhelper.h" 0012 #include "utils.h" 0013 0014 using namespace Akonadi; 0015 using namespace Akonadi::Server; 0016 0017 TagFetchHelper::TagFetchHelper(Connection *connection, const Scope &scope, const Protocol::TagFetchScope &fetchScope) 0018 : mConnection(connection) 0019 , mScope(scope) 0020 , mFetchScope(fetchScope) 0021 { 0022 } 0023 0024 QSqlQuery TagFetchHelper::buildAttributeQuery() const 0025 { 0026 QueryBuilder qb(TagAttribute::tableName()); 0027 qb.addColumn(TagAttribute::tagIdFullColumnName()); 0028 qb.addColumn(TagAttribute::typeFullColumnName()); 0029 qb.addColumn(TagAttribute::valueFullColumnName()); 0030 qb.addSortColumn(TagAttribute::tagIdFullColumnName(), Query::Descending); 0031 qb.addJoin(QueryBuilder::InnerJoin, Tag::tableName(), TagAttribute::tagIdFullColumnName(), Tag::idFullColumnName()); 0032 TagQueryHelper::scopeToQuery(mScope, mConnection->context(), qb); 0033 0034 if (!qb.exec()) { 0035 throw HandlerException("Unable to list tag attributes"); 0036 } 0037 0038 qb.query().next(); 0039 return qb.query(); 0040 } 0041 0042 QSqlQuery TagFetchHelper::buildAttributeQuery(qint64 id, const Protocol::TagFetchScope &fetchScope) 0043 { 0044 QueryBuilder qb(TagAttribute::tableName()); 0045 qb.addColumn(TagAttribute::tagIdColumn()); 0046 qb.addColumn(TagAttribute::typeColumn()); 0047 qb.addColumn(TagAttribute::valueColumn()); 0048 qb.addSortColumn(TagAttribute::tagIdColumn(), Query::Descending); 0049 0050 qb.addValueCondition(TagAttribute::tagIdColumn(), Query::Equals, id); 0051 if (!fetchScope.fetchAllAttributes() && !fetchScope.attributes().isEmpty()) { 0052 QVariantList typeNames; 0053 const auto attrs = fetchScope.attributes(); 0054 std::transform(attrs.cbegin(), attrs.cend(), std::back_inserter(typeNames), [](const QByteArray &ba) { 0055 return QVariant(ba); 0056 }); 0057 qb.addValueCondition(TagAttribute::typeColumn(), Query::In, typeNames); 0058 } 0059 0060 if (!qb.exec()) { 0061 throw HandlerException("Unable to list tag attributes"); 0062 } 0063 0064 qb.query().next(); 0065 return qb.query(); 0066 } 0067 0068 QSqlQuery TagFetchHelper::buildTagQuery() 0069 { 0070 QueryBuilder qb(Tag::tableName()); 0071 qb.addColumn(Tag::idFullColumnName()); 0072 qb.addColumn(Tag::gidFullColumnName()); 0073 qb.addColumn(Tag::parentIdFullColumnName()); 0074 0075 qb.addJoin(QueryBuilder::InnerJoin, TagType::tableName(), Tag::typeIdFullColumnName(), TagType::idFullColumnName()); 0076 qb.addColumn(TagType::nameFullColumnName()); 0077 0078 // Expose tag's remote ID only to resources 0079 if (mFetchScope.fetchRemoteID() && mConnection->context().resource().isValid()) { 0080 qb.addColumn(TagRemoteIdResourceRelation::remoteIdFullColumnName()); 0081 Query::Condition joinCondition; 0082 joinCondition.addValueCondition(TagRemoteIdResourceRelation::resourceIdFullColumnName(), Query::Equals, mConnection->context().resource().id()); 0083 joinCondition.addColumnCondition(TagRemoteIdResourceRelation::tagIdFullColumnName(), Query::Equals, Tag::idFullColumnName()); 0084 qb.addJoin(QueryBuilder::LeftJoin, TagRemoteIdResourceRelation::tableName(), joinCondition); 0085 } 0086 0087 qb.addSortColumn(Tag::idFullColumnName(), Query::Descending); 0088 TagQueryHelper::scopeToQuery(mScope, mConnection->context(), qb); 0089 if (!qb.exec()) { 0090 throw HandlerException("Unable to list tags"); 0091 } 0092 0093 qb.query().next(); 0094 return qb.query(); 0095 } 0096 0097 QMap<QByteArray, QByteArray> TagFetchHelper::fetchTagAttributes(qint64 tagId, const Protocol::TagFetchScope &fetchScope) 0098 { 0099 QMap<QByteArray, QByteArray> attributes; 0100 0101 QSqlQuery attributeQuery = buildAttributeQuery(tagId, fetchScope); 0102 while (attributeQuery.isValid()) { 0103 attributes.insert(Utils::variantToByteArray(attributeQuery.value(1)), Utils::variantToByteArray(attributeQuery.value(2))); 0104 attributeQuery.next(); 0105 } 0106 attributeQuery.finish(); 0107 return attributes; 0108 } 0109 0110 bool TagFetchHelper::fetchTags() 0111 { 0112 QSqlQuery tagQuery = buildTagQuery(); 0113 QSqlQuery attributeQuery; 0114 if (!mFetchScope.fetchIdOnly()) { 0115 attributeQuery = buildAttributeQuery(); 0116 } 0117 0118 while (tagQuery.isValid()) { 0119 const qint64 tagId = tagQuery.value(0).toLongLong(); 0120 Protocol::FetchTagsResponse response; 0121 response.setId(tagId); 0122 if (!mFetchScope.fetchIdOnly()) { 0123 response.setGid(Utils::variantToByteArray(tagQuery.value(1))); 0124 if (tagQuery.value(2).isNull()) { 0125 // client indicates invalid or null parent as ID -1 0126 response.setParentId(-1); 0127 } else { 0128 response.setParentId(tagQuery.value(2).toLongLong()); 0129 } 0130 response.setType(Utils::variantToByteArray(tagQuery.value(3))); 0131 if (mFetchScope.fetchRemoteID() && mConnection->context().resource().isValid()) { 0132 response.setRemoteId(Utils::variantToByteArray(tagQuery.value(4))); 0133 } 0134 0135 QMap<QByteArray, QByteArray> tagAttributes; 0136 while (attributeQuery.isValid()) { 0137 const qint64 id = attributeQuery.value(0).toLongLong(); 0138 if (id > tagId) { 0139 attributeQuery.next(); 0140 continue; 0141 } else if (id < tagId) { 0142 break; 0143 } 0144 0145 tagAttributes.insert(Utils::variantToByteArray(attributeQuery.value(1)), Utils::variantToByteArray(attributeQuery.value(2))); 0146 attributeQuery.next(); 0147 } 0148 0149 response.setAttributes(tagAttributes); 0150 } 0151 0152 mConnection->sendResponse(std::move(response)); 0153 0154 tagQuery.next(); 0155 } 0156 attributeQuery.finish(); 0157 tagQuery.finish(); 0158 0159 return true; 0160 }