File indexing completed on 2025-01-05 04:46:59

0001 /*
0002     SPDX-FileCopyrightText: 2009 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "itemqueryhelper.h"
0008 
0009 #include "collectionqueryhelper.h"
0010 #include "commandcontext.h"
0011 #include "handler.h"
0012 #include "storage/querybuilder.h"
0013 #include "storage/queryhelper.h"
0014 
0015 #include "private/imapset_p.h"
0016 #include "private/scope_p.h"
0017 
0018 using namespace Akonadi;
0019 using namespace Akonadi::Server;
0020 
0021 void ItemQueryHelper::itemSetToQuery(const ImapSet &set, QueryBuilder &qb, const Collection &collection)
0022 {
0023     if (!set.isEmpty()) {
0024         QueryHelper::setToQuery(set, qb.getTableWithColumn(PimItem::idColumn()), qb);
0025     }
0026     if (collection.isValid()) {
0027         if (collection.isVirtual() || collection.resource().isVirtual()) {
0028             qb.addJoin(QueryBuilder::InnerJoin,
0029                        CollectionPimItemRelation::tableName(),
0030                        CollectionPimItemRelation::rightFullColumnName(),
0031                        qb.getTableWithColumn(PimItem::idColumn()));
0032             qb.addValueCondition(CollectionPimItemRelation::leftFullColumnName(), Query::Equals, collection.id());
0033         } else {
0034             qb.addValueCondition(qb.getTableWithColumn(PimItem::collectionIdColumn()), Query::Equals, collection.id());
0035         }
0036     }
0037 }
0038 
0039 void ItemQueryHelper::itemSetToQuery(const ImapSet &set, const CommandContext &context, QueryBuilder &qb)
0040 {
0041     if (context.collectionId() >= 0) {
0042         itemSetToQuery(set, qb, context.collection());
0043     } else {
0044         itemSetToQuery(set, qb);
0045     }
0046 
0047     const auto tagId = context.tagId();
0048     if (tagId.has_value()) {
0049         // When querying for items by tag, only return matches from that resource
0050         if (context.resource().isValid()) {
0051             qb.addJoin(QueryBuilder::InnerJoin, Collection::tableName(), qb.getTableWithColumn(PimItem::collectionIdColumn()), Collection::idFullColumnName());
0052             qb.addValueCondition(Collection::resourceIdFullColumnName(), Query::Equals, context.resource().id());
0053         }
0054         qb.addJoin(QueryBuilder::InnerJoin,
0055                    PimItemTagRelation::tableName(),
0056                    qb.getTableWithColumn(PimItem::idColumn()),
0057                    PimItemTagRelation::leftFullColumnName());
0058         qb.addValueCondition(PimItemTagRelation::rightFullColumnName(), Query::Equals, *tagId);
0059     }
0060 }
0061 
0062 void ItemQueryHelper::remoteIdToQuery(const QStringList &rids, const CommandContext &context, QueryBuilder &qb)
0063 {
0064     if (rids.size() == 1) {
0065         qb.addValueCondition(qb.getTableWithColumn(PimItem::remoteIdColumn()), Query::Equals, rids.first());
0066     } else {
0067         qb.addValueCondition(qb.getTableWithColumn(PimItem::remoteIdColumn()), Query::In, rids);
0068     }
0069 
0070     if (context.resource().isValid()) {
0071         qb.addJoin(QueryBuilder::InnerJoin, Collection::tableName(), qb.getTableWithColumn(PimItem::collectionIdColumn()), Collection::idFullColumnName());
0072         qb.addValueCondition(Collection::resourceIdFullColumnName(), Query::Equals, context.resource().id());
0073     }
0074     if (context.collectionId() > 0) {
0075         qb.addValueCondition(qb.getTableWithColumn(PimItem::collectionIdColumn()), Query::Equals, context.collectionId());
0076     }
0077 
0078     const auto tagId = context.tagId();
0079     if (tagId.has_value()) {
0080         qb.addJoin(QueryBuilder::InnerJoin,
0081                    PimItemTagRelation::tableName(),
0082                    qb.getTableWithColumn(PimItem::idColumn()),
0083                    PimItemTagRelation::leftFullColumnName());
0084         qb.addValueCondition(PimItemTagRelation::rightFullColumnName(), Query::Equals, *tagId);
0085     }
0086 }
0087 
0088 void ItemQueryHelper::gidToQuery(const QStringList &gids, const CommandContext &context, QueryBuilder &qb)
0089 {
0090     if (gids.size() == 1) {
0091         qb.addValueCondition(qb.getTableWithColumn(PimItem::gidColumn()), Query::Equals, gids.first());
0092     } else {
0093         qb.addValueCondition(qb.getTableWithColumn(PimItem::gidColumn()), Query::In, gids);
0094     }
0095 
0096     const auto tagId = context.tagId();
0097     if (tagId.has_value()) {
0098         // When querying for items by tag, only return matches from that resource
0099         if (context.resource().isValid()) {
0100             qb.addJoin(QueryBuilder::InnerJoin, Collection::tableName(), qb.getTableWithColumn(PimItem::collectionIdColumn()), Collection::idFullColumnName());
0101             qb.addValueCondition(Collection::resourceIdFullColumnName(), Query::Equals, context.resource().id());
0102         }
0103         qb.addJoin(QueryBuilder::InnerJoin,
0104                    PimItemTagRelation::tableName(),
0105                    qb.getTableWithColumn(PimItem::idColumn()),
0106                    PimItemTagRelation::leftFullColumnName());
0107         qb.addValueCondition(PimItemTagRelation::rightFullColumnName(), Query::Equals, *tagId);
0108     }
0109 }
0110 
0111 void ItemQueryHelper::scopeToQuery(const Scope &scope, const CommandContext &context, QueryBuilder &qb)
0112 {
0113     // Handle fetch by collection/tag
0114     if (scope.scope() == Scope::Invalid && !context.isEmpty()) {
0115         itemSetToQuery(ImapSet(), context, qb);
0116         return;
0117     }
0118 
0119     if (scope.scope() == Scope::Uid) {
0120         itemSetToQuery(scope.uidSet(), context, qb);
0121         return;
0122     }
0123 
0124     if (scope.scope() == Scope::Gid) {
0125         ItemQueryHelper::gidToQuery(scope.gidSet(), context, qb);
0126         return;
0127     }
0128 
0129     if (context.collectionId() <= 0 && !context.resource().isValid()) {
0130         throw HandlerException("Operations based on remote identifiers require a resource or collection context");
0131     }
0132 
0133     if (scope.scope() == Scope::Rid) {
0134         ItemQueryHelper::remoteIdToQuery(scope.ridSet(), context, qb);
0135         return;
0136     } else if (scope.scope() == Scope::HierarchicalRid) {
0137         QList<Scope::HRID> hridChain = scope.hridChain();
0138         const Scope::HRID itemHRID = hridChain.takeFirst();
0139         const Collection parentCol = CollectionQueryHelper::resolveHierarchicalRID(hridChain, context.resource().id());
0140         const Collection oldSelection = context.collection();
0141         CommandContext tmpContext(context);
0142         tmpContext.setCollection(parentCol);
0143         remoteIdToQuery(QStringList() << itemHRID.remoteId, tmpContext, qb);
0144         return;
0145     }
0146 
0147     throw HandlerException("Dude, WTF?!?");
0148 }